home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / dock.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-29  |  118.6 KB  |  4,455 lines

  1. /* dock.c- built-in Dock module for WindowMaker
  2.  *
  3.  *  Window Maker window manager
  4.  *
  5.  *  Copyright (c) 1997, 1998 Alfredo K. Kojima
  6.  *  Copyright (c) 1998, 1999 Dan Pascu
  7.  *
  8.  *  This program is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2 of the License, or
  11.  *  (at your option) any later version.
  12.  *
  13.  *  This program is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; if not, write to the Free Software
  20.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  21.  *  USA.
  22.  */
  23.  
  24.  
  25. #include "wconfig.h"
  26.  
  27. #include <X11/Xlib.h>
  28. #include <X11/Xutil.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <unistd.h>
  32. #include <math.h>
  33. #include <limits.h>
  34.  
  35. #ifndef PATH_MAX
  36. #define PATH_MAX DEFAULT_PATH_MAX
  37. #endif
  38.  
  39. #include "WindowMaker.h"
  40. #include "wcore.h"
  41. #include "window.h"
  42. #include "icon.h"
  43. #include "appicon.h"
  44. #include "actions.h"
  45. #include "stacking.h"
  46. #include "dock.h"
  47. #include "dialog.h"
  48. #include "funcs.h"
  49. #include "properties.h"
  50. #include "menu.h"
  51. #include "client.h"
  52. #include "defaults.h"
  53. #include "workspace.h"
  54. #include "framewin.h"
  55. #include "superfluous.h"
  56. #include "wmsound.h"
  57.  
  58.  
  59. #include <proplist.h>
  60.  
  61.  
  62.  
  63.  
  64. /**** Local variables ****/
  65. #define CLIP_REWIND       1
  66. #define CLIP_IDLE         0
  67. #define CLIP_FORWARD      2
  68.  
  69.  
  70. /**** Global variables ****/
  71.  
  72. /* in dockedapp.c */
  73. extern void DestroyDockAppSettingsPanel();
  74.  
  75. extern void ShowDockAppSettingsPanel(WAppIcon *aicon);
  76.  
  77.  
  78. extern XContext wWinContext;
  79.  
  80. extern Cursor wCursor[WCUR_LAST];
  81.  
  82. extern WPreferences wPreferences;
  83.  
  84. extern XContext wWinContext;
  85.  
  86. #ifdef OFFIX_DND
  87. extern Atom _XA_DND_PROTOCOL;
  88. #endif
  89.  
  90.  
  91. #define MOD_MASK wPreferences.modifier_mask
  92.  
  93. extern void appIconMouseDown(WObjDescriptor *desc, XEvent *event);
  94.  
  95. #define ICON_SIZE wPreferences.icon_size
  96.  
  97.  
  98. /***** Local variables ****/
  99.  
  100. static proplist_t dCommand=NULL;
  101. #ifdef OFFIX_DND
  102. static proplist_t dDropCommand=NULL;
  103. #endif
  104. static proplist_t dAutoLaunch, dLock;
  105. static proplist_t dName, dForced, dBuggyApplication, dYes, dNo;
  106. static proplist_t dHost, dDock, dClip;
  107. static proplist_t dAutoAttractIcons;
  108.  
  109. static proplist_t dPosition, dApplications, dLowered, dCollapsed, dAutoCollapse;
  110.  
  111. static proplist_t dAutoRaiseLower, dOmnipresent;
  112.  
  113. static void dockIconPaint(WAppIcon *btn);
  114.  
  115. static void iconMouseDown(WObjDescriptor *desc, XEvent *event);
  116.  
  117. static pid_t execCommand(WAppIcon *btn, char *command, WSavedState *state);
  118.  
  119. static void trackDeadProcess(pid_t pid, unsigned char status, WDock *dock);
  120.  
  121. static int getClipButton(int px, int py);
  122.  
  123. static void toggleLowered(WDock *dock);
  124.  
  125. static void toggleCollapsed(WDock *dock);
  126.  
  127. static void clipIconExpose(WObjDescriptor *desc, XEvent *event);
  128.  
  129. static void clipLeave(WDock *dock);
  130.  
  131. static void handleClipChangeWorkspace(WScreen *scr, XEvent *event);
  132.  
  133. Bool moveIconBetweenDocks(WDock *src, WDock *dest, WAppIcon *icon, int x, int y);
  134.  
  135. static void clipEnterNotify(WObjDescriptor *desc, XEvent *event);
  136. static void clipLeaveNotify(WObjDescriptor *desc, XEvent *event);
  137. static void clipAutoCollapse(void *cdata);
  138. static void clipAutoExpand(void *cdata);
  139. static void launchDockedApplication(WAppIcon *btn);
  140.  
  141. static void clipAutoLower(void *cdata);
  142. static void clipAutoRaise(void *cdata);
  143.  
  144. static void showClipBalloon(WDock *dock, int workspace);
  145.  
  146. #ifdef OFFIX_DND
  147.  
  148. #define DndNotDnd       -1
  149. #define DndUnknown      0
  150. #define DndRawData      1
  151. #define DndFile         2
  152. #define DndFiles        3
  153. #define DndText         4
  154. #define DndDir          5
  155. #define DndLink         6
  156. #define DndExe          7
  157.  
  158. #define DndEND          8
  159.  
  160. #endif /* OFFIX_DND */
  161.  
  162.  
  163.  
  164. static void
  165. make_keys()
  166. {
  167.     if (dCommand!=NULL)
  168.     return;
  169.  
  170.     dCommand = PLRetain(PLMakeString("Command"));
  171. #ifdef OFFIX_DND
  172.     dDropCommand = PLRetain(PLMakeString("DropCommand"));
  173. #endif
  174.     dLock = PLRetain(PLMakeString("Lock"));
  175.     dAutoLaunch = PLRetain(PLMakeString("AutoLaunch"));
  176.     dName = PLRetain(PLMakeString("Name"));
  177.     dForced = PLRetain(PLMakeString("Forced"));
  178.     dBuggyApplication = PLRetain(PLMakeString("BuggyApplication"));
  179.     dYes = PLRetain(PLMakeString("Yes"));
  180.     dNo = PLRetain(PLMakeString("No"));
  181.     dHost = PLRetain(PLMakeString("Host"));
  182.  
  183.     dPosition = PLMakeString("Position");
  184.     dApplications = PLMakeString("Applications");
  185.     dLowered = PLMakeString("Lowered");
  186.     dCollapsed = PLMakeString("Collapsed");
  187.     dAutoCollapse = PLMakeString("AutoCollapse");
  188.     dAutoRaiseLower = PLMakeString("AutoRaiseLower");
  189.     dAutoAttractIcons = PLMakeString("AutoAttractIcons");
  190.  
  191.     dOmnipresent = PLMakeString("Omnipresent");
  192.  
  193.     dDock = PLMakeString("Dock");
  194.     dClip = PLMakeString("Clip");
  195. }
  196.  
  197.  
  198.  
  199. static void
  200. renameCallback(WMenu *menu, WMenuEntry *entry)
  201. {
  202.     WDock *dock = entry->clientdata;
  203.     char buffer[128];
  204.     int wspace;
  205.     char *name;
  206.  
  207.     assert(entry->clientdata!=NULL);
  208.  
  209.     wspace = dock->screen_ptr->current_workspace;
  210.  
  211.     name = wstrdup(dock->screen_ptr->workspaces[wspace]->name);
  212.  
  213.     sprintf(buffer, _("Type the name for workspace %i:"), wspace+1);
  214.     if (wInputDialog(dock->screen_ptr, _("Rename Workspace"), buffer,
  215.              &name)) {
  216.     wWorkspaceRename(dock->screen_ptr, wspace, name);
  217.     }
  218.     if (name) {
  219.     free(name);
  220.     }
  221. }
  222.  
  223.  
  224. static void
  225. toggleLoweredCallback(WMenu *menu, WMenuEntry *entry)
  226. {
  227.     assert(entry->clientdata!=NULL);
  228.  
  229.     toggleLowered(entry->clientdata);
  230.  
  231.     wMenuPaint(menu);
  232. }
  233.  
  234.  
  235.  
  236. static void
  237. killCallback(WMenu *menu, WMenuEntry *entry)
  238. {
  239.     WAppIcon *icon;
  240. #ifdef REDUCE_APPICONS
  241.     WAppIconAppList *tapplist;
  242.  
  243.     extern Atom _XA_WM_DELETE_WINDOW;
  244. #else
  245.     char *buffer;
  246. #endif
  247.  
  248.     if (!WCHECK_STATE(WSTATE_NORMAL))
  249.     return;
  250.  
  251.     assert(entry->clientdata!=NULL);
  252.  
  253.     icon = (WAppIcon*)entry->clientdata;
  254.  
  255.     icon->editing = 1;
  256.  
  257.     WCHANGE_STATE(WSTATE_MODAL);
  258.  
  259. #ifdef REDUCE_APPICONS
  260.     /* Send a delete message to the main window of each application
  261.      * bound to this docked appicon. - cls
  262.      */
  263.     tapplist = icon->applist;
  264.     while (tapplist != NULL) {
  265.     if (tapplist->wapp->main_window_desc != NULL) {
  266.         if (tapplist->wapp->main_window_desc->protocols.DELETE_WINDOW) {
  267.         wClientSendProtocol(tapplist->wapp->main_window_desc,
  268.                     _XA_WM_DELETE_WINDOW, CurrentTime);
  269.         } else {
  270.         wClientKill(tapplist->wapp->main_window_desc);
  271.         }
  272.     }
  273.     tapplist = tapplist->next;
  274.     }
  275. #else
  276.     buffer = wstrappend(icon->wm_class,
  277.             _(" will be forcibly closed.\n"
  278.               "Any unsaved changes will be lost.\n"
  279.               "Please confirm."));
  280.  
  281.     if (wPreferences.dont_confirm_kill
  282.     || wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
  283.               buffer, _("Yes"), _("No"), NULL)==WAPRDefault) {
  284.     if (icon->icon && icon->icon->owner) {
  285.         wClientKill(icon->icon->owner);
  286.     }
  287.     }
  288. #endif /* !REDUCE_APPICONS */
  289.  
  290.     icon->editing = 0;
  291.  
  292.     WCHANGE_STATE(WSTATE_NORMAL);
  293. }
  294.  
  295.  
  296. /* TODO: replace this function with a member of the dock struct */
  297. static int
  298. numberOfSelectedIcons(WDock *dock)
  299. {
  300.     WAppIcon *aicon;
  301.     int i, n;
  302.  
  303.     n = 0;
  304.     for (i=1; i<dock->max_icons; i++) {
  305.         aicon = dock->icon_array[i];
  306.         if (aicon && aicon->icon->selected) {
  307.             n++;
  308.         }
  309.     }
  310.  
  311.     return n;
  312. }
  313.  
  314.  
  315. static WMBag*
  316. getSelected(WDock *dock)
  317. {
  318.     WMBag *ret = WMCreateBag(8);
  319.     WAppIcon *btn;
  320.     int i;
  321.  
  322.     for (i=1; i<dock->max_icons; i++) {
  323.         btn = dock->icon_array[i];
  324.         if (btn && btn->icon->selected) {
  325.         WMPutInBag(ret, btn);
  326.         }
  327.     }
  328.  
  329.     return ret;
  330. }
  331.  
  332.  
  333. static void
  334. paintClipButtons(WAppIcon *clipIcon, Bool lpushed, Bool rpushed)
  335. {
  336.     Window win = clipIcon->icon->core->window;
  337.     WScreen *scr = clipIcon->icon->core->screen_ptr;
  338.     XPoint p[4];
  339.     int pt = CLIP_BUTTON_SIZE*ICON_SIZE/64;
  340.     int tp = ICON_SIZE - pt;
  341.     int as = pt - 15; /* 15 = 5+5+5 */
  342.     GC gc = scr->clip_title_gc;
  343. #ifdef GRADIENT_CLIP_ARROW
  344.     Bool collapsed = clipIcon->dock->collapsed;
  345. #endif
  346.  
  347.     if (rpushed) {
  348.     p[0].x = tp+1;
  349.     p[0].y = 1;
  350.     p[1].x = ICON_SIZE-2;
  351.     p[1].y = 1;
  352.     p[2].x = ICON_SIZE-2;
  353.     p[2].y = pt-1;
  354.     } else if (lpushed) {
  355.     p[0].x = 1;
  356.     p[0].y = tp;
  357.     p[1].x = pt;
  358.     p[1].y = ICON_SIZE-2;
  359.     p[2].x = 1;
  360.     p[2].y = ICON_SIZE-2;
  361.     }
  362.     if (lpushed || rpushed) {
  363.     XSetForeground(dpy, scr->draw_gc, scr->white_pixel);
  364.     XFillPolygon(dpy, win, scr->draw_gc, p, 3, Convex, CoordModeOrigin);
  365.     XSetForeground(dpy, scr->draw_gc, scr->black_pixel);
  366.     }
  367. #ifdef GRADIENT_CLIP_ARROW
  368.     if (!collapsed) {
  369.     XSetFillStyle(dpy, scr->copy_gc, FillTiled);
  370.     XSetTile(dpy, scr->copy_gc, scr->clip_arrow_gradient);
  371.     XSetClipMask(dpy, scr->copy_gc, None);
  372.     gc = scr->copy_gc;
  373.     }
  374. #endif /* GRADIENT_CLIP_ARROW */
  375.  
  376.     /* top right arrow */
  377.     p[0].x = p[3].x = ICON_SIZE-5-as;
  378.     p[0].y = p[3].y = 5;
  379.     p[1].x = ICON_SIZE-6;
  380.     p[1].y = 5;
  381.     p[2].x = ICON_SIZE-6;
  382.     p[2].y = 4+as;
  383.     if (rpushed) {
  384.         XFillPolygon(dpy, win, scr->draw_gc, p, 3, Convex, CoordModeOrigin);
  385.         XDrawLines(dpy, win, scr->draw_gc, p, 4, CoordModeOrigin);
  386.     } else {
  387. #ifdef GRADIENT_CLIP_ARROW
  388.     if (!collapsed)
  389.         XSetTSOrigin(dpy, gc, ICON_SIZE-6-as, 5);
  390. #endif
  391.     XFillPolygon(dpy, win, gc, p,3,Convex,CoordModeOrigin);
  392.         XDrawLines(dpy, win, gc, p,4,CoordModeOrigin);
  393.     }
  394.  
  395.     /* bottom left arrow */
  396.     p[0].x = p[3].x = 5;
  397.     p[0].y = p[3].y = ICON_SIZE-5-as;
  398.     p[1].x = 5;
  399.     p[1].y = ICON_SIZE-6;
  400.     p[2].x = 4+as;
  401.     p[2].y = ICON_SIZE-6;
  402.     if (lpushed) {
  403.     XFillPolygon(dpy, win, scr->draw_gc, p, 3, Convex, CoordModeOrigin);
  404.         XDrawLines(dpy, win, scr->draw_gc, p, 4, CoordModeOrigin);
  405.     } else {
  406. #ifdef GRADIENT_CLIP_ARROW
  407.     if (!collapsed)
  408.         XSetTSOrigin(dpy, gc, 5, ICON_SIZE-6-as);
  409. #endif
  410.         XFillPolygon(dpy, win, gc, p,3,Convex,CoordModeOrigin);
  411.         XDrawLines(dpy, win, gc, p,4,CoordModeOrigin);
  412.     }
  413. #ifdef GRADIENT_CLIP_ARROW
  414.     if (!collapsed)
  415.     XSetFillStyle(dpy, scr->copy_gc, FillSolid);
  416. #endif
  417. }
  418.  
  419.  
  420. RImage*
  421. wClipMakeTile(WScreen *scr, RImage *normalTile)
  422. {
  423.     RImage *tile = RCloneImage(normalTile);
  424.     RColor black;
  425.     RColor dark;
  426.     RColor light;
  427.     int pt, tp;
  428.     int as;
  429.  
  430.     pt = CLIP_BUTTON_SIZE*wPreferences.icon_size/64;
  431.     tp = wPreferences.icon_size-1 - pt;
  432.     as = pt - 15;
  433.  
  434.     black.alpha = 255;
  435.     black.red = black.green = black.blue = 0;
  436.  
  437.     dark.alpha = 0;
  438.     dark.red = dark.green = dark.blue = 60;
  439.  
  440.     light.alpha = 0;
  441.     light.red = light.green = light.blue = 80;
  442.  
  443.  
  444.     /* top right */
  445.     ROperateLine(tile, RSubtractOperation, tp, 0, wPreferences.icon_size-2,
  446.          pt-1, &dark);
  447.     RDrawLine(tile, tp-1, 0, wPreferences.icon_size-1, pt+1, &black);
  448.     ROperateLine(tile, RAddOperation, tp, 2, wPreferences.icon_size-3,
  449.          pt, &light);
  450.  
  451.     /* arrow bevel */
  452.     ROperateLine(tile, RSubtractOperation, ICON_SIZE - 7 - as, 4,
  453.                  ICON_SIZE - 5, 4, &dark);
  454.     ROperateLine(tile, RSubtractOperation, ICON_SIZE - 6 - as, 5,
  455.          ICON_SIZE - 5, 6 + as, &dark);
  456.     ROperateLine(tile, RAddOperation, ICON_SIZE - 5, 4, ICON_SIZE - 5, 6 + as,
  457.          &light);
  458.  
  459.     /* bottom left */
  460.     ROperateLine(tile, RAddOperation, 2, tp+2, pt-2,
  461.          wPreferences.icon_size-3, &dark);
  462.     RDrawLine(tile, 0, tp-1, pt+1, wPreferences.icon_size-1, &black);
  463.     ROperateLine(tile, RSubtractOperation, 0, tp-2, pt+1,
  464.          wPreferences.icon_size-2, &light);
  465.  
  466.     /* arrow bevel */
  467.     ROperateLine(tile, RSubtractOperation, 4, ICON_SIZE - 7 - as, 4,
  468.                  ICON_SIZE - 5, &dark);
  469.     ROperateLine(tile, RSubtractOperation, 5, ICON_SIZE - 6 - as,
  470.          6 + as, ICON_SIZE - 5, &dark);
  471.     ROperateLine(tile, RAddOperation, 4, ICON_SIZE - 5, 6 + as, ICON_SIZE - 5,
  472.          &light);
  473.  
  474.     return tile;
  475. }
  476.  
  477.  
  478. static void
  479. omnipresentCallback(WMenu *menu, WMenuEntry *entry)
  480. {
  481.     WAppIcon *clickedIcon = entry->clientdata;
  482.     WAppIcon *aicon;
  483.     WDock *dock;
  484.     WMBag *selectedIcons;
  485.     int failed;
  486.     int i;
  487.  
  488.     assert(entry->clientdata!=NULL);
  489.  
  490.     dock = clickedIcon->dock;
  491.  
  492.     selectedIcons = getSelected(dock);
  493.  
  494.     if (!WMGetBagItemCount(selectedIcons))
  495.         WMPutInBag(selectedIcons, clickedIcon);
  496.  
  497.     failed = 0;
  498.     for (i = 0; i < WMGetBagItemCount(selectedIcons); i++) {
  499.         aicon = WMGetFromBag(selectedIcons, i);
  500.  
  501.         if (wClipMakeIconOmnipresent(aicon, !aicon->omnipresent) == WO_FAILED)
  502.             failed++;
  503.         else if (aicon->icon->selected)
  504.             wIconSelect(aicon->icon);
  505.     }
  506.     WMFreeBag(selectedIcons);
  507.  
  508.     if (failed > 1) {
  509.         wMessageDialog(dock->screen_ptr, _("Warning"),
  510.                        _("Some icons cannot be made omnipresent. "
  511.                          "Please make sure that no other icon is "
  512.                          "docked in the same positions on the other "
  513.                          "workspaces and the Clip is not full in "
  514.                          "some workspace."),
  515.                        _("OK"), NULL, NULL);
  516.     } else if (failed == 1) {
  517.         wMessageDialog(dock->screen_ptr, _("Warning"),
  518.                        _("Icon cannot be made omnipresent. "
  519.                          "Please make sure that no other icon is "
  520.                          "docked in the same position on the other "
  521.                          "workspaces and the Clip is not full in "
  522.                          "some workspace."),
  523.                        _("OK"), NULL, NULL);
  524.     }
  525. }
  526.  
  527.  
  528. static void
  529. removeIconsCallback(WMenu *menu, WMenuEntry *entry)
  530. {
  531.     WAppIcon *clickedIcon = (WAppIcon*)entry->clientdata;
  532.     WDock *dock;
  533.     WAppIcon *aicon;
  534.     WMBag *selectedIcons;
  535.     int keepit;
  536.     WMBagIterator it;
  537.  
  538.     assert(clickedIcon!=NULL);
  539.  
  540.     dock = clickedIcon->dock;
  541.  
  542.     selectedIcons = getSelected(dock);
  543.  
  544.     if (WMGetBagItemCount(selectedIcons)) {
  545.     if (wMessageDialog(dock->screen_ptr, _("Workspace Clip"),
  546.                _("All selected icons will be removed!"),
  547.                _("OK"), _("Cancel"), NULL)!=WAPRDefault) {
  548.         WMFreeBag(selectedIcons);
  549.         return;
  550.     }
  551.     } else {
  552.     if (clickedIcon->xindex==0 && clickedIcon->yindex==0) {
  553.         WMFreeBag(selectedIcons);
  554.         return;
  555.     }
  556.     WMPutInBag(selectedIcons, clickedIcon);
  557.     }
  558.  
  559.     WM_ITERATE_BAG(selectedIcons, aicon, it) {
  560.         keepit = aicon->running && wApplicationOf(aicon->main_window);
  561.         wDockDetach(dock, aicon);
  562.         if (keepit) {
  563.             PlaceIcon(dock->screen_ptr, &aicon->x_pos, &aicon->y_pos);
  564.             XMoveWindow(dpy, aicon->icon->core->window,
  565.                         aicon->x_pos, aicon->y_pos);
  566.             if (!dock->mapped || dock->collapsed)
  567.                 XMapWindow(dpy, aicon->icon->core->window);
  568.         }
  569.     }
  570.     WMFreeBag(selectedIcons);
  571.  
  572.     if (wPreferences.auto_arrange_icons)
  573.         wArrangeIcons(dock->screen_ptr, True);
  574. }
  575.  
  576.  
  577. static void
  578. keepIconsCallback(WMenu *menu, WMenuEntry *entry)
  579. {
  580.     WAppIcon *clickedIcon = (WAppIcon*)entry->clientdata;
  581.     WDock *dock;
  582.     WAppIcon *aicon;
  583.     WMBag *selectedIcons;
  584.     WMBagIterator it;
  585.  
  586.     assert(clickedIcon!=NULL);
  587.     dock = clickedIcon->dock;
  588.  
  589.     selectedIcons = getSelected(dock);
  590.  
  591.     if (!WMGetBagItemCount(selectedIcons) 
  592.     && clickedIcon!=dock->screen_ptr->clip_icon) {
  593.     char *command = NULL;
  594.     
  595.     if (!clickedIcon->command && !clickedIcon->editing) {
  596.         clickedIcon->editing = 1;
  597.         if (wInputDialog(dock->screen_ptr, _("Keep Icon"),
  598.                  _("Type the command used to launch the application"),
  599.                  &command)) {
  600.         if (command && (command[0]==0 ||
  601.                 (command[0]=='-' && command[1]==0))) {
  602.             free(command);
  603.             command = NULL;
  604.         }
  605.         clickedIcon->command = command;
  606.         clickedIcon->editing = 0;
  607.         } else {
  608.         clickedIcon->editing = 0;
  609.         if (command)
  610.             free(command);
  611.         WMFreeBag(selectedIcons);
  612.         return;
  613.         }
  614.     }
  615.  
  616.     WMPutInBag(selectedIcons, clickedIcon);
  617.     }
  618.  
  619.     WM_ITERATE_BAG(selectedIcons, aicon, it) {
  620.     if (aicon->icon->selected)
  621.             wIconSelect(aicon->icon);
  622.         if (aicon && aicon->attracted && aicon->command) {
  623.         aicon->attracted = 0;
  624.         if (aicon->icon->shadowed) {
  625.         aicon->icon->shadowed = 0;
  626.         aicon->icon->force_paint = 1;
  627.         wAppIconPaint(aicon);
  628.         }
  629.         }
  630.     }
  631.     WMFreeBag(selectedIcons);
  632. }
  633.  
  634.  
  635.  
  636.  
  637. static void
  638. toggleAutoAttractCallback(WMenu *menu, WMenuEntry *entry)
  639. {
  640.     WDock *dock = (WDock*)entry->clientdata;
  641.  
  642.     assert(entry->clientdata!=NULL);
  643.  
  644.     dock->attract_icons = !dock->attract_icons;
  645.     /*if (!dock->attract_icons)
  646.         dock->keep_attracted = 0;*/
  647.  
  648.     entry->flags.indicator_on = dock->attract_icons;
  649.  
  650.     wMenuPaint(menu);
  651. }
  652.  
  653.  
  654. static void
  655. selectCallback(WMenu *menu, WMenuEntry *entry)
  656. {
  657.     WAppIcon *icon = (WAppIcon*)entry->clientdata;
  658.  
  659.     assert(icon!=NULL);
  660.  
  661.     wIconSelect(icon->icon);
  662.  
  663.     wMenuPaint(menu);
  664. }
  665.  
  666.  
  667. static void
  668. colectIconsCallback(WMenu *menu, WMenuEntry *entry)
  669. {
  670.     WAppIcon *clickedIcon = (WAppIcon*)entry->clientdata;
  671.     WDock *clip;
  672.     WAppIcon *aicon;
  673.     int x, y, x_pos, y_pos;
  674.  
  675.     assert(entry->clientdata!=NULL);
  676.     clip = clickedIcon->dock;
  677.  
  678.     aicon = clip->screen_ptr->app_icon_list;
  679.  
  680.     while (aicon) {
  681.         if (!aicon->docked && wDockFindFreeSlot(clip, &x, &y)) {
  682.             x_pos = clip->x_pos + x*ICON_SIZE;
  683.             y_pos = clip->y_pos + y*ICON_SIZE;
  684.             if (aicon->x_pos != x_pos || aicon->y_pos != y_pos) {
  685. #ifdef ANIMATIONS
  686.                 if (wPreferences.no_animations) {
  687.                     XMoveWindow(dpy, aicon->icon->core->window, x_pos, y_pos);
  688.                 } else {
  689.                     SlideWindow(aicon->icon->core->window,
  690.                                 aicon->x_pos, aicon->y_pos, x_pos, y_pos);
  691.                 }
  692. #else
  693.                 XMoveWindow(dpy, aicon->icon->core->window, x_pos, y_pos);
  694. #endif /* ANIMATIONS */
  695.             }
  696.             aicon->attracted = 1;
  697.         if (!aicon->icon->shadowed) {
  698.                 aicon->icon->shadowed = 1;
  699.                 aicon->icon->force_paint = 1;
  700.                 /* We don't do an wAppIconPaint() here because it's in
  701.                  * wDockAttachIcon(). -Dan
  702.                  */
  703.             }
  704.             wDockAttachIcon(clip, aicon, x, y);
  705.             if (clip->collapsed || !clip->mapped)
  706.                 XUnmapWindow(dpy, aicon->icon->core->window);
  707.         }
  708.         aicon = aicon->next;
  709.     }
  710. }
  711.  
  712.  
  713. static void
  714. selectIconsCallback(WMenu *menu, WMenuEntry *entry)
  715. {
  716.     WAppIcon *clickedIcon = (WAppIcon*)entry->clientdata;
  717.     WDock *dock;
  718.     WMBag *selectedIcons;
  719.     WAppIcon *btn;
  720.     int i;
  721.  
  722.     assert(clickedIcon!=NULL);
  723.     dock = clickedIcon->dock;
  724.  
  725.     selectedIcons = getSelected(dock);
  726.  
  727.     if (!WMGetBagItemCount(selectedIcons)) {
  728.         for (i=1; i<dock->max_icons; i++) {
  729.             btn = dock->icon_array[i];
  730.             if (btn && !btn->icon->selected) {
  731.         wIconSelect(btn->icon);
  732.             }
  733.         }
  734.     } else {
  735.         for (i = 0; i < WMGetBagItemCount(selectedIcons); i++) {
  736.             btn = WMGetFromBag(selectedIcons, i);
  737.         wIconSelect(btn->icon);
  738.         }
  739.     }
  740.     WMFreeBag(selectedIcons);
  741.  
  742.     wMenuPaint(menu);
  743. }
  744.  
  745.  
  746. static void
  747. toggleCollapsedCallback(WMenu *menu, WMenuEntry *entry)
  748. {
  749.     assert(entry->clientdata!=NULL);
  750.  
  751.     toggleCollapsed(entry->clientdata);
  752.  
  753.     entry->flags.indicator_on = ((WDock*)entry->clientdata)->collapsed;
  754.  
  755.     wMenuPaint(menu);
  756. }
  757.  
  758.  
  759. static void
  760. toggleAutoCollapseCallback(WMenu *menu, WMenuEntry *entry)
  761. {
  762.     WDock *dock;
  763.     assert(entry->clientdata!=NULL);
  764.  
  765.     dock = (WDock*) entry->clientdata;
  766.  
  767.     dock->auto_collapse = !dock->auto_collapse;
  768.  
  769.     entry->flags.indicator_on = ((WDock*)entry->clientdata)->auto_collapse;
  770.  
  771.     wMenuPaint(menu);
  772. }
  773.  
  774.  
  775. static void
  776. toggleAutoRaiseLowerCallback(WMenu *menu, WMenuEntry *entry)
  777. {
  778.     WDock *dock;
  779.     assert(entry->clientdata!=NULL);
  780.  
  781.     dock = (WDock*) entry->clientdata;
  782.  
  783.     dock->auto_raise_lower = !dock->auto_raise_lower;
  784.  
  785.     entry->flags.indicator_on = ((WDock*)entry->clientdata)->auto_raise_lower;
  786.  
  787.     wMenuPaint(menu);
  788. }
  789.  
  790.  
  791. static void
  792. launchCallback(WMenu *menu, WMenuEntry *entry)
  793. {
  794.     WAppIcon *btn = (WAppIcon*)entry->clientdata;
  795.  
  796.     launchDockedApplication(btn);
  797. }
  798.  
  799.  
  800. static void
  801. settingsCallback(WMenu *menu, WMenuEntry *entry)
  802. {
  803.     WAppIcon *btn = (WAppIcon*)entry->clientdata;
  804.  
  805.     if (btn->editing)
  806.     return;
  807.     ShowDockAppSettingsPanel(btn);
  808. }
  809.  
  810.  
  811. static void
  812. hideCallback(WMenu *menu, WMenuEntry *entry)
  813. {
  814.     WApplication *wapp;
  815.     WAppIcon *btn = (WAppIcon*)entry->clientdata;
  816.  
  817.     wapp = wApplicationOf(btn->icon->owner->main_window);
  818.  
  819.     if (wapp->flags.hidden) {
  820.     wWorkspaceChange(btn->icon->core->screen_ptr,wapp->last_workspace);
  821.     wUnhideApplication(wapp, False, False);
  822.     } else {
  823.     wHideApplication(wapp);
  824.     }
  825. }
  826.  
  827.  
  828. static void
  829. unhideHereCallback(WMenu *menu, WMenuEntry *entry)
  830. {
  831.     WApplication *wapp;
  832.     WAppIcon *btn = (WAppIcon*)entry->clientdata;
  833.  
  834.     wapp = wApplicationOf(btn->icon->owner->main_window);
  835.  
  836.     wUnhideApplication(wapp, False, True);
  837. }
  838.  
  839.  
  840. WAppIcon*
  841. mainIconCreate(WScreen *scr, int type)
  842. {
  843.     WAppIcon *btn;
  844.     int x_pos;
  845.  
  846.     if (type == WM_CLIP) {
  847.         if (scr->clip_icon)
  848.             return scr->clip_icon;
  849.         btn = wAppIconCreateForDock(scr, NULL, "Logo", "WMClip", TILE_CLIP);
  850.         btn->icon->core->descriptor.handle_expose = clipIconExpose;
  851.         btn->icon->core->descriptor.handle_enternotify = clipEnterNotify;
  852.         btn->icon->core->descriptor.handle_leavenotify = clipLeaveNotify;
  853.         /*x_pos = scr->scr_width - ICON_SIZE*2 - DOCK_EXTRA_SPACE;*/
  854.         x_pos = 0;
  855.     } else {
  856.         btn = wAppIconCreateForDock(scr, NULL, "Logo", "WMDock", TILE_NORMAL);
  857.         x_pos = scr->scr_width - ICON_SIZE - DOCK_EXTRA_SPACE;
  858.     }
  859.  
  860.     btn->xindex = 0;
  861.     btn->yindex = 0;
  862.  
  863.     btn->icon->core->descriptor.handle_mousedown = iconMouseDown;
  864.     btn->icon->core->descriptor.parent_type = WCLASS_DOCK_ICON;
  865.     btn->icon->core->descriptor.parent = btn;
  866.     /*ChangeStackingLevel(btn->icon->core, WMDockLevel);*/
  867.     XMapWindow(dpy, btn->icon->core->window);
  868.     btn->x_pos = x_pos;
  869.     btn->y_pos = 0;
  870.     btn->docked = 1;
  871.     if (type == WM_CLIP)
  872.         scr->clip_icon = btn;
  873.  
  874.     return btn;
  875. }
  876.  
  877.  
  878. static void
  879. switchWSCommand(WMenu *menu, WMenuEntry *entry)
  880. {
  881.     WAppIcon *btn, *icon = (WAppIcon*) entry->clientdata;
  882.     WScreen *scr = icon->icon->core->screen_ptr;
  883.     WDock *src, *dest;
  884.     WMBag *selectedIcons;
  885.     int x, y;
  886.  
  887.     if (entry->order == scr->current_workspace)
  888.         return;
  889.     src = icon->dock;
  890.     dest = scr->workspaces[entry->order]->clip;
  891.  
  892.     selectedIcons = getSelected(src);
  893.  
  894.     if (WMGetBagItemCount(selectedIcons)) {
  895.     int i;
  896.     for (i = 0; i < WMGetBagItemCount(selectedIcons); i++) {
  897.             btn = WMGetFromBag(selectedIcons, i);
  898.             if (wDockFindFreeSlot(dest, &x, &y)) {
  899.                 moveIconBetweenDocks(src, dest, btn, x, y);
  900.                 XUnmapWindow(dpy, btn->icon->core->window);
  901.             }
  902.         }
  903.     } else if (icon != scr->clip_icon) {
  904.         if (wDockFindFreeSlot(dest, &x, &y)) {
  905.             moveIconBetweenDocks(src, dest, icon, x, y);
  906.             XUnmapWindow(dpy, icon->icon->core->window);
  907.         }
  908.     }
  909.     WMFreeBag(selectedIcons);
  910. }
  911.  
  912.  
  913.  
  914. static void
  915. launchDockedApplication(WAppIcon *btn)
  916. {
  917.     WScreen *scr = btn->icon->core->screen_ptr;
  918.  
  919.     if (!btn->launching && btn->command!=NULL) {
  920.     if (!btn->forced_dock) {
  921.         btn->relaunching = btn->running;
  922.         btn->running = 1;
  923.     }
  924.     if (btn->wm_instance || btn->wm_class) {
  925.         WWindowAttributes attr;
  926.         memset(&attr, 0, sizeof(WWindowAttributes));
  927.         wDefaultFillAttributes(scr, btn->wm_instance, btn->wm_class,
  928.                    &attr, NULL, True);
  929.  
  930.         if (!attr.no_appicon && !btn->buggy_app)
  931.         btn->launching = 1;
  932.         else
  933.         btn->running = 0;
  934.     }
  935.     btn->drop_launch = 0;
  936.         scr->last_dock = btn->dock;
  937.         btn->pid = execCommand(btn, btn->command, NULL);
  938.         if (btn->pid>0) {
  939.         if (btn->buggy_app) {
  940.         /* give feedback that the app was launched */
  941.         btn->launching = 1;
  942.         dockIconPaint(btn);
  943.         btn->launching = 0;
  944.         WMAddTimerHandler(200, (WMCallback*)dockIconPaint, btn);
  945.         } else {
  946.         dockIconPaint(btn);
  947.         }
  948.         } else {
  949.         wwarning(_("could not launch application %s\n"), btn->command);
  950.             btn->launching = 0;
  951.             if (!btn->relaunching)
  952.                 btn->running = 0;
  953.         }
  954.     }
  955. }
  956.  
  957.  
  958.  
  959. static void
  960. updateWorkspaceMenu(WMenu *menu, WAppIcon *icon)
  961. {
  962.     WScreen *scr = menu->frame->screen_ptr;
  963.     char title[MAX_WORKSPACENAME_WIDTH+1];
  964.     int i;
  965.  
  966.     if (!menu || !icon)
  967.         return;
  968.  
  969.     for (i=0; i<scr->workspace_count; i++) {
  970.         if (i < menu->entry_no) {
  971.             if (strcmp(menu->entries[i]->text,scr->workspaces[i]->name)!=0) {
  972.                 free(menu->entries[i]->text);
  973.                 strcpy(title, scr->workspaces[i]->name);
  974.                 menu->entries[i]->text = wstrdup(title);
  975.                 menu->flags.realized = 0;
  976.             }
  977.             menu->entries[i]->clientdata = (void*)icon;
  978.         } else {
  979.             strcpy(title, scr->workspaces[i]->name);
  980.  
  981.             wMenuAddCallback(menu, title, switchWSCommand, (void*)icon);
  982.  
  983.             menu->flags.realized = 0;
  984.         }
  985.         if (i == scr->current_workspace) {
  986.             wMenuSetEnabled(menu, i, False);
  987.         } else {
  988.             wMenuSetEnabled(menu, i, True);
  989.         }
  990.     }
  991.  
  992.     if (!menu->flags.realized)
  993.         wMenuRealize(menu);
  994. }
  995.  
  996.  
  997. static WMenu*
  998. makeWorkspaceMenu(WScreen *scr)
  999. {
  1000.     WMenu *menu;
  1001.  
  1002.     menu = wMenuCreate(scr, NULL, False);
  1003.     if (!menu)
  1004.         wwarning(_("could not create workspace submenu for Clip menu"));
  1005.  
  1006.     wMenuAddCallback(menu, "", switchWSCommand, (void*)scr->clip_icon);
  1007.  
  1008.     menu->flags.realized = 0;
  1009.     wMenuRealize(menu);
  1010.  
  1011.     return menu;
  1012. }
  1013.  
  1014.  
  1015. static void
  1016. updateClipOptionsMenu(WMenu *menu, WDock *dock)
  1017. {
  1018.     WMenuEntry *entry;
  1019.     int index = 0;
  1020.  
  1021.     if (!menu || !dock)
  1022.         return;
  1023.  
  1024.     /* keep on top */
  1025.     entry = menu->entries[index];
  1026.     if (dock->lowered) {
  1027.     entry->text = _("Keep on Top");
  1028.     } else {
  1029.     entry->text = _("Allow Lowering");
  1030.     }
  1031.     entry->clientdata = dock;
  1032.  
  1033.     /* collapsed */
  1034.     entry = menu->entries[++index];
  1035.     entry->flags.indicator_on = dock->collapsed;
  1036.     entry->clientdata = dock;
  1037.  
  1038.     /* auto-collapse */
  1039.     entry = menu->entries[++index];
  1040.     entry->flags.indicator_on = dock->auto_collapse;
  1041.     entry->clientdata = dock;
  1042.  
  1043.     /* auto-raise/lower */
  1044.     entry = menu->entries[++index];
  1045.     entry->flags.indicator_on = dock->auto_raise_lower;
  1046.     entry->clientdata = dock;
  1047.  
  1048.     /* attract icons */
  1049.     entry = menu->entries[++index];
  1050.     entry->flags.indicator_on = dock->attract_icons;
  1051.     entry->clientdata = dock;
  1052.  
  1053.     menu->flags.realized = 0;
  1054.     wMenuRealize(menu);
  1055. }
  1056.  
  1057.  
  1058. static WMenu*
  1059. makeClipOptionsMenu(WScreen *scr)
  1060. {
  1061.     WMenu *menu;
  1062.     WMenuEntry *entry;
  1063.  
  1064.     menu = wMenuCreate(scr, NULL, False);
  1065.     if (!menu) {
  1066.         wwarning(_("could not create options submenu for Clip menu"));
  1067.     return NULL;
  1068.     }
  1069.  
  1070.     entry = wMenuAddCallback(menu, _("Keep on Top"),
  1071.                              toggleLoweredCallback, NULL);
  1072.  
  1073.     entry = wMenuAddCallback(menu, _("Collapsed"),
  1074.                              toggleCollapsedCallback, NULL);
  1075.     entry->flags.indicator = 1;
  1076.     entry->flags.indicator_on = 1;
  1077.     entry->flags.indicator_type = MI_CHECK;
  1078.  
  1079.     entry = wMenuAddCallback(menu, _("AutoCollapse"),
  1080.                              toggleAutoCollapseCallback, NULL);
  1081.     entry->flags.indicator = 1;
  1082.     entry->flags.indicator_on = 1;
  1083.     entry->flags.indicator_type = MI_CHECK;
  1084.  
  1085.     entry = wMenuAddCallback(menu, _("AutoRaiseLower"),
  1086.                              toggleAutoRaiseLowerCallback, NULL);
  1087.     entry->flags.indicator = 1;
  1088.     entry->flags.indicator_on = 1;
  1089.     entry->flags.indicator_type = MI_CHECK;
  1090.  
  1091.     entry = wMenuAddCallback(menu, _("AutoAttract Icons"),
  1092.                              toggleAutoAttractCallback, NULL);
  1093.     entry->flags.indicator = 1;
  1094.     entry->flags.indicator_on = 1;
  1095.     entry->flags.indicator_type = MI_CHECK;
  1096.  
  1097.     menu->flags.realized = 0;
  1098.     wMenuRealize(menu);
  1099.  
  1100.     return menu;
  1101. }
  1102.  
  1103.  
  1104. static WMenu*
  1105. dockMenuCreate(WScreen *scr, int type)
  1106. {
  1107.     WMenu *menu;
  1108.     WMenuEntry *entry;
  1109.  
  1110.     if (type == WM_CLIP && scr->clip_menu)
  1111.         return scr->clip_menu;
  1112.  
  1113.     menu = wMenuCreate(scr, NULL, False);
  1114.     if (type != WM_CLIP) {
  1115.         entry = wMenuAddCallback(menu, _("Keep on Top"),
  1116.                                  toggleLoweredCallback, NULL);
  1117.     } else {
  1118.         entry = wMenuAddCallback(menu, _("Clip Options"), NULL, NULL);
  1119.         scr->clip_options = makeClipOptionsMenu(scr);
  1120.         if (scr->clip_options)
  1121.             wMenuEntrySetCascade(menu, entry, scr->clip_options);
  1122.  
  1123.         entry = wMenuAddCallback(menu, _("Rename Workspace"), renameCallback,
  1124.                                  NULL);
  1125.         free(entry->text);
  1126.         entry->text = _("Rename Workspace");
  1127.  
  1128.         entry = wMenuAddCallback(menu, _("Selected"), selectCallback, NULL);
  1129.         entry->flags.indicator = 1;
  1130.         entry->flags.indicator_on = 1;
  1131.         entry->flags.indicator_type = MI_CHECK;
  1132.  
  1133.         entry = wMenuAddCallback(menu, _("Select All Icons"),
  1134.                                  selectIconsCallback, NULL);
  1135.         free(entry->text);
  1136.         entry->text = _("Select All Icons");
  1137.  
  1138.         entry = wMenuAddCallback(menu, _("Keep Icon"), keepIconsCallback, NULL);
  1139.         free(entry->text);
  1140.         entry->text = _("Keep Icon");
  1141.  
  1142.         entry = wMenuAddCallback(menu, _("Move Icon To"), NULL, NULL);
  1143.         free(entry->text);
  1144.         entry->text = _("Move Icon To");
  1145.         scr->clip_submenu = makeWorkspaceMenu(scr);
  1146.         if (scr->clip_submenu)
  1147.             wMenuEntrySetCascade(menu, entry, scr->clip_submenu);
  1148.  
  1149.         entry = wMenuAddCallback(menu, _("Remove Icon"), removeIconsCallback,
  1150.                                  NULL);
  1151.         free(entry->text);
  1152.         entry->text = _("Remove Icon");
  1153.  
  1154.         wMenuAddCallback(menu, _("Attract Icons"), colectIconsCallback, NULL);
  1155.     }
  1156.  
  1157.     wMenuAddCallback(menu, _("Launch"), launchCallback, NULL);
  1158.  
  1159.     wMenuAddCallback(menu, _("Unhide Here"), unhideHereCallback, NULL);
  1160.  
  1161.     entry = wMenuAddCallback(menu, _("Hide"), hideCallback, NULL);
  1162.     free(entry->text);
  1163.     entry->text = _("Hide");
  1164.  
  1165.     wMenuAddCallback(menu, _("Settings..."), settingsCallback, NULL);
  1166.  
  1167.     wMenuAddCallback(menu, _("Kill"), killCallback, NULL);
  1168.  
  1169.     if (type == WM_CLIP)
  1170.         scr->clip_menu = menu;
  1171.  
  1172.     return menu;
  1173. }
  1174.  
  1175.  
  1176. WDock*
  1177. wDockCreate(WScreen *scr, int type)
  1178. {
  1179.     WDock *dock;
  1180.     WAppIcon *btn;
  1181.     int icon_count;
  1182.  
  1183.     make_keys();
  1184.  
  1185.     dock = wmalloc(sizeof(WDock));
  1186.     memset(dock, 0, sizeof(WDock));
  1187.  
  1188.     if (type == WM_CLIP)
  1189.         icon_count = CLIP_MAX_ICONS;
  1190.     else
  1191.         icon_count = scr->scr_height/wPreferences.icon_size;
  1192.  
  1193.     dock->icon_array = wmalloc(sizeof(WAppIcon*)*icon_count);
  1194.     memset(dock->icon_array, 0, sizeof(WAppIcon*)*icon_count);
  1195.  
  1196.     dock->max_icons = icon_count;
  1197.  
  1198.     btn = mainIconCreate(scr, type);
  1199.  
  1200.     btn->dock = dock;
  1201.  
  1202.     dock->x_pos = btn->x_pos;
  1203.     dock->y_pos = btn->y_pos;
  1204.     dock->screen_ptr = scr;
  1205.     dock->type = type;
  1206.     dock->icon_count = 1;
  1207.     dock->on_right_side = 1;
  1208.     dock->collapsed = 0;
  1209.     dock->auto_collapse = 0;
  1210.     dock->auto_collapse_magic = NULL;
  1211.     dock->auto_raise_lower = 0;
  1212.     dock->auto_lower_magic = NULL;
  1213.     dock->auto_raise_magic = NULL;
  1214.     dock->attract_icons = 0;
  1215.     dock->lowered = 1;
  1216.     dock->icon_array[0] = btn;
  1217.     wRaiseFrame(btn->icon->core);
  1218.     XMoveWindow(dpy, btn->icon->core->window, btn->x_pos, btn->y_pos);
  1219.  
  1220.     /* create dock menu */
  1221.     dock->menu = dockMenuCreate(scr, type);
  1222.  
  1223.     return dock;
  1224. }
  1225.  
  1226.  
  1227. void
  1228. wDockDestroy(WDock *dock)
  1229. {
  1230.     int i;
  1231.     WAppIcon *aicon;
  1232.  
  1233.     for (i=(dock->type == WM_CLIP) ? 1 : 0; i<dock->max_icons; i++) {
  1234.         aicon = dock->icon_array[i];
  1235.         if (aicon) {
  1236.             int keepit = aicon->running && wApplicationOf(aicon->main_window);
  1237.             wDockDetach(dock, aicon);
  1238.             if (keepit) {
  1239.                 PlaceIcon(dock->screen_ptr, &aicon->x_pos, &aicon->y_pos);
  1240.                 XMoveWindow(dpy, aicon->icon->core->window,
  1241.                             aicon->x_pos, aicon->y_pos);
  1242.                 if (!dock->mapped || dock->collapsed)
  1243.                     XMapWindow(dpy, aicon->icon->core->window);
  1244.             }
  1245.         }
  1246.     }
  1247.     if (wPreferences.auto_arrange_icons)
  1248.         wArrangeIcons(dock->screen_ptr, True);
  1249.     free(dock->icon_array);
  1250.     if (dock->menu && dock->type!=WM_CLIP)
  1251.         wMenuDestroy(dock->menu, True);
  1252.     if (dock->screen_ptr->last_dock == dock)
  1253.         dock->screen_ptr->last_dock = NULL;
  1254.     free(dock);
  1255. }
  1256.  
  1257.  
  1258. void
  1259. wClipIconPaint(WAppIcon *aicon)
  1260. {
  1261.     WScreen *scr = aicon->icon->core->screen_ptr;
  1262.     WWorkspace *workspace = scr->workspaces[scr->current_workspace];
  1263.     GC gc;
  1264.     Window win = aicon->icon->core->window;
  1265.     int length, nlength;
  1266.     char *ws_name, ws_number[10];
  1267.     int ty, tx;
  1268.  
  1269.     wIconPaint(aicon->icon);
  1270.  
  1271.     length = strlen(workspace->name);
  1272.     ws_name = malloc(length + 1);
  1273.     sprintf(ws_name, "%s", workspace->name);
  1274.     sprintf(ws_number, "%i", scr->current_workspace + 1);
  1275.     nlength = strlen(ws_number);
  1276.  
  1277.     gc = scr->clip_title_gc;
  1278.  
  1279.     if (!workspace->clip->collapsed)
  1280.         XSetForeground(dpy, gc, scr->clip_title_pixel[CLIP_NORMAL]);
  1281.     else
  1282.         XSetForeground(dpy, gc, scr->clip_title_pixel[CLIP_COLLAPSED]);
  1283.  
  1284.     ty = ICON_SIZE - WMFontHeight(scr->clip_title_font) - 3;
  1285.  
  1286.     tx = CLIP_BUTTON_SIZE*ICON_SIZE/64;
  1287.  
  1288.     WMDrawString(scr->wmscreen, win, gc, scr->clip_title_font, tx,
  1289.          ty, ws_name, length);
  1290.  
  1291.     tx = (ICON_SIZE/2 - WMWidthOfString(scr->clip_title_font, ws_number,
  1292.                     nlength))/2;
  1293.  
  1294.     WMDrawString(scr->wmscreen, win, gc, scr->clip_title_font, tx,
  1295.          2, ws_number, nlength);
  1296.  
  1297.     free(ws_name);
  1298.  
  1299.     if (aicon->launching) {
  1300.     XFillRectangle(dpy, aicon->icon->core->window, scr->stipple_gc,
  1301.                0, 0, wPreferences.icon_size, wPreferences.icon_size);
  1302.     }
  1303.     paintClipButtons(aicon, aicon->dock->lclip_button_pushed,
  1304.              aicon->dock->rclip_button_pushed);
  1305. }
  1306.  
  1307.  
  1308. static void
  1309. clipIconExpose(WObjDescriptor *desc, XEvent *event)
  1310. {
  1311.     wClipIconPaint(desc->parent);
  1312. }
  1313.  
  1314.  
  1315. static void
  1316. dockIconPaint(WAppIcon *btn)
  1317. {
  1318.     if (btn == btn->icon->core->screen_ptr->clip_icon)
  1319.         wClipIconPaint(btn);
  1320.     else
  1321.         wAppIconPaint(btn);
  1322. }
  1323.  
  1324.  
  1325. static proplist_t
  1326. make_icon_state(WAppIcon *btn)
  1327. {
  1328.     proplist_t node = NULL;
  1329.     proplist_t command, autolaunch, lock, name, forced, host, position, buggy;
  1330.     proplist_t omnipresent;
  1331.     char *tmp;
  1332.     char buffer[64];
  1333.  
  1334.     if (btn) {
  1335.     if (!btn->command)
  1336.         command = PLMakeString("-");
  1337.     else
  1338.         command = PLMakeString(btn->command);
  1339.  
  1340.     autolaunch = btn->auto_launch ? dYes : dNo;
  1341.  
  1342.     lock = btn->lock ? dYes : dNo;
  1343.  
  1344.     tmp = EscapeWM_CLASS(btn->wm_instance, btn->wm_class);
  1345.  
  1346.     name = PLMakeString(tmp);
  1347.  
  1348.     free(tmp);
  1349.  
  1350.     forced = btn->forced_dock ? dYes : dNo;
  1351.  
  1352.     buggy = btn->buggy_app ? dYes : dNo;
  1353.  
  1354.         if (btn == btn->icon->core->screen_ptr->clip_icon)
  1355.             sprintf(buffer, "%i,%i", btn->x_pos, btn->y_pos);
  1356.         else
  1357.             sprintf(buffer, "%hi,%hi", btn->xindex, btn->yindex);
  1358.         position = PLMakeString(buffer);
  1359.  
  1360.         node = PLMakeDictionaryFromEntries(dCommand, command,
  1361.                                            dName, name,
  1362.                                            dAutoLaunch, autolaunch,
  1363.                        dLock, lock,
  1364.                                            dForced, forced,
  1365.                        dBuggyApplication, buggy,
  1366.                                            dPosition, position,
  1367.                                            NULL);
  1368.         PLRelease(command);
  1369.         PLRelease(name);
  1370.         PLRelease(position);
  1371.  
  1372.         omnipresent = btn->omnipresent ? dYes : dNo;
  1373.         if (btn->dock != btn->icon->core->screen_ptr->dock &&
  1374.             (btn->xindex != 0 || btn->yindex != 0))
  1375.             PLInsertDictionaryEntry(node, dOmnipresent, omnipresent);
  1376.  
  1377. #ifdef OFFIX_DND
  1378.         if (btn->dnd_command) {
  1379.             command = PLMakeString(btn->dnd_command);
  1380.             PLInsertDictionaryEntry(node, dDropCommand, command);
  1381.             PLRelease(command);
  1382.     }
  1383. #endif /* OFFIX_DND */
  1384.  
  1385.     if (btn->client_machine && btn->remote_start) {
  1386.         host = PLMakeString(btn->client_machine);
  1387.         PLInsertDictionaryEntry(node, dHost, host);
  1388.         PLRelease(host);
  1389.     }
  1390.     }
  1391.  
  1392.     return node;
  1393. }
  1394.  
  1395.  
  1396. static proplist_t
  1397. dockSaveState(WDock *dock)
  1398. {
  1399.     int i;
  1400.     proplist_t icon_info;
  1401.     proplist_t list=NULL, dock_state=NULL;
  1402.     proplist_t value, key;
  1403.     char buffer[256];
  1404.  
  1405.     list = PLMakeArrayFromElements(NULL);
  1406.  
  1407.     for (i=(dock->type==WM_DOCK ? 0 : 1); i<dock->max_icons; i++) {
  1408.         WAppIcon *btn = dock->icon_array[i];
  1409.  
  1410.         if (!btn || btn->attracted)
  1411.             continue;
  1412.  
  1413.         if ((icon_info = make_icon_state(dock->icon_array[i]))) {
  1414.             list = PLAppendArrayElement(list, icon_info);
  1415.             PLRelease(icon_info);
  1416.         }
  1417.     }
  1418.     
  1419.     dock_state = PLMakeDictionaryFromEntries(dApplications, list, 
  1420.                          NULL);
  1421.  
  1422.     if (dock->type == WM_DOCK) {
  1423.     sprintf(buffer, "Applications%i", dock->screen_ptr->scr_height);
  1424.     key = PLMakeString(buffer);
  1425.     PLInsertDictionaryEntry(dock_state, key, list);
  1426.     PLRelease(key);
  1427.  
  1428.     
  1429.         sprintf(buffer, "%i,%i", (dock->on_right_side ? -ICON_SIZE : 0),
  1430.                                   dock->y_pos);
  1431.         value = PLMakeString(buffer);
  1432.         PLInsertDictionaryEntry(dock_state, dPosition, value);
  1433.         PLRelease(value);
  1434.     }
  1435.     PLRelease(list);
  1436.  
  1437.  
  1438.     value = (dock->lowered ? dYes : dNo);
  1439.     PLInsertDictionaryEntry(dock_state, dLowered, value);
  1440.  
  1441.     if (dock->type == WM_CLIP) {
  1442.         value = (dock->collapsed ? dYes : dNo);
  1443.         PLInsertDictionaryEntry(dock_state, dCollapsed, value);
  1444.  
  1445.         value = (dock->auto_collapse ? dYes : dNo);
  1446.     PLInsertDictionaryEntry(dock_state, dAutoCollapse, value);
  1447.  
  1448.         value = (dock->auto_raise_lower ? dYes : dNo);
  1449.     PLInsertDictionaryEntry(dock_state, dAutoRaiseLower, value);
  1450.  
  1451.         value = (dock->attract_icons ? dYes : dNo);
  1452.         PLInsertDictionaryEntry(dock_state, dAutoAttractIcons, value);
  1453.     }
  1454.  
  1455.     return dock_state;
  1456. }
  1457.  
  1458.  
  1459. void
  1460. wDockSaveState(WScreen *scr, proplist_t old_state)
  1461. {
  1462.     proplist_t dock_state;
  1463.     proplist_t keys;
  1464.  
  1465.     dock_state = dockSaveState(scr->dock);
  1466.  
  1467.     /*
  1468.      * Copy saved states of docks with different sizes.
  1469.      */
  1470.     if (old_state) {
  1471.     int i;
  1472.     proplist_t tmp;
  1473.  
  1474.     keys = PLGetAllDictionaryKeys(old_state);
  1475.     for (i = 0; i < PLGetNumberOfElements(keys); i++) {
  1476.         tmp = PLGetArrayElement(keys, i);
  1477.  
  1478.         if (strncasecmp(PLGetString(tmp), "applications", 12) == 0
  1479.         && !PLGetDictionaryEntry(dock_state, tmp)) {
  1480.  
  1481.         PLInsertDictionaryEntry(dock_state,
  1482.                     tmp, 
  1483.                     PLGetDictionaryEntry(old_state, tmp));
  1484.         }
  1485.     }
  1486.     PLRelease(keys);
  1487.     }
  1488.     
  1489.  
  1490.     PLInsertDictionaryEntry(scr->session_state, dDock, dock_state);
  1491.  
  1492.     PLRelease(dock_state);
  1493. }
  1494.  
  1495.  
  1496. void
  1497. wClipSaveState(WScreen *scr)
  1498. {
  1499.     proplist_t clip_state;
  1500.  
  1501.     clip_state = make_icon_state(scr->clip_icon);
  1502.  
  1503.     PLInsertDictionaryEntry(scr->session_state, dClip, clip_state);
  1504.  
  1505.     PLRelease(clip_state);
  1506. }
  1507.  
  1508.  
  1509. proplist_t
  1510. wClipSaveWorkspaceState(WScreen *scr, int workspace)
  1511. {
  1512.     return dockSaveState(scr->workspaces[workspace]->clip);
  1513. }
  1514.  
  1515.  
  1516. static Bool
  1517. getBooleanDockValue(proplist_t value, proplist_t key)
  1518. {
  1519.     if (value) {
  1520.         if (PLIsString(value)) {
  1521.             if (strcasecmp(PLGetString(value), "YES")==0)
  1522.                 return True;
  1523.         } else {
  1524.             wwarning(_("bad value in docked icon state info %s"),
  1525.                      PLGetString(key));
  1526.         }
  1527.     }
  1528.     return False;
  1529. }
  1530.  
  1531.  
  1532. static WAppIcon*
  1533. restore_icon_state(WScreen *scr, proplist_t info, int type, int index)
  1534. {
  1535.     WAppIcon *aicon;
  1536.     proplist_t cmd, value;
  1537.  
  1538.  
  1539.     cmd = PLGetDictionaryEntry(info, dCommand);
  1540.     if (!cmd || !PLIsString(cmd)) {
  1541.     return NULL;
  1542.     }
  1543.  
  1544.     /* parse window name */
  1545.     value = PLGetDictionaryEntry(info, dName);
  1546.     if (!value)
  1547.     return NULL;
  1548.  
  1549.     {
  1550.     char *wclass, *winstance;
  1551.     char *command;
  1552.  
  1553.     ParseWindowName(value, &winstance, &wclass, "dock");
  1554.     
  1555.     if (!winstance && !wclass) {
  1556.         return NULL;
  1557.     }
  1558.  
  1559.     /* get commands */
  1560.  
  1561.     if (cmd)
  1562.         command = wstrdup(PLGetString(cmd));
  1563.     else
  1564.         command = NULL;
  1565.  
  1566.     if (!command || strcmp(command, "-")==0) {
  1567.         if (command)
  1568.         free(command);
  1569.         if (wclass)
  1570.         free(wclass);
  1571.         if (winstance)
  1572.         free(winstance);
  1573.  
  1574.         return NULL;
  1575.     }
  1576.  
  1577.     aicon = wAppIconCreateForDock(scr, command, winstance, wclass,
  1578.                       TILE_NORMAL);
  1579.     if (wclass)
  1580.         free(wclass);
  1581.     if (winstance)
  1582.         free(winstance);
  1583.     if (command)
  1584.         free(command);
  1585.     }
  1586.  
  1587.     aicon->icon->core->descriptor.handle_mousedown = iconMouseDown;
  1588.     if (type == WM_CLIP) {
  1589.         aicon->icon->core->descriptor.handle_enternotify = clipEnterNotify;
  1590.         aicon->icon->core->descriptor.handle_leavenotify = clipLeaveNotify;
  1591.     }
  1592.     aicon->icon->core->descriptor.parent_type = WCLASS_DOCK_ICON;
  1593.     aicon->icon->core->descriptor.parent = aicon;
  1594.  
  1595.  
  1596. #ifdef OFFIX_DND
  1597.     cmd = PLGetDictionaryEntry(info, dDropCommand);
  1598.     if (cmd)
  1599.     aicon->dnd_command = wstrdup(PLGetString(cmd));
  1600. #endif
  1601.  
  1602.     /* check auto launch */
  1603.     value = PLGetDictionaryEntry(info, dAutoLaunch);
  1604.  
  1605.     aicon->auto_launch = getBooleanDockValue(value, dAutoLaunch);
  1606.  
  1607.     /* check lock */
  1608.     value = PLGetDictionaryEntry(info, dLock);
  1609.  
  1610.     aicon->lock = getBooleanDockValue(value, dLock);
  1611.  
  1612.     /* check if it wasn't normally docked */
  1613.     value = PLGetDictionaryEntry(info, dForced);
  1614.  
  1615.     aicon->forced_dock = getBooleanDockValue(value, dForced);
  1616.  
  1617.     /* check if we can rely on the stuff in the app */
  1618.     value = PLGetDictionaryEntry(info, dBuggyApplication);
  1619.  
  1620.     aicon->buggy_app = getBooleanDockValue(value, dBuggyApplication);
  1621.  
  1622.     /* get position in the dock */
  1623.     value = PLGetDictionaryEntry(info, dPosition);
  1624.     if (value && PLIsString(value)) {
  1625.         if (sscanf(PLGetString(value), "%hi,%hi", &aicon->xindex,
  1626.                    &aicon->yindex)!=2)
  1627.             wwarning(_("bad value in docked icon state info %s"),
  1628.                      PLGetString(dPosition));
  1629.  
  1630.         /* check position sanity */
  1631.         /* incomplete section! */
  1632.         if (type == WM_DOCK) {
  1633.             aicon->xindex = 0;
  1634.             if (aicon->yindex < 0)
  1635.                 wwarning(_("bad value in docked icon position %i,%i"),
  1636.                          aicon->xindex, aicon->yindex);
  1637.         }
  1638.     } else {
  1639.         aicon->yindex = index;
  1640.         aicon->xindex = 0;
  1641.     }
  1642.  
  1643.     /* check if icon is omnipresent */
  1644.     value = PLGetDictionaryEntry(info, dOmnipresent);
  1645.  
  1646.     aicon->omnipresent = getBooleanDockValue(value, dOmnipresent);
  1647.  
  1648.     aicon->running = 0;
  1649.     aicon->docked = 1;
  1650.  
  1651.     return aicon;
  1652. }
  1653.  
  1654.  
  1655. #define COMPLAIN(key) wwarning(_("bad value in dock state info:%s"), key)
  1656.  
  1657.  
  1658. WAppIcon*
  1659. wClipRestoreState(WScreen *scr, proplist_t clip_state)
  1660. {
  1661.     WAppIcon *icon;
  1662.     proplist_t value;
  1663.  
  1664.  
  1665.     icon = mainIconCreate(scr, WM_CLIP);
  1666.  
  1667.     if (!clip_state)
  1668.     return icon;
  1669.     else
  1670.         PLRetain(clip_state);
  1671.  
  1672.     /* restore position */
  1673.  
  1674.     value = PLGetDictionaryEntry(clip_state, dPosition);
  1675.  
  1676.     if (value) {
  1677.     if (!PLIsString(value))
  1678.         COMPLAIN("Position");
  1679.     else {
  1680.         if (sscanf(PLGetString(value), "%i,%i", &icon->x_pos,
  1681.                &icon->y_pos)!=2)
  1682.         COMPLAIN("Position");
  1683.  
  1684.         /* check position sanity */
  1685.         if (icon->y_pos < 0)
  1686.         icon->y_pos = 0;
  1687.         else if (icon->y_pos > scr->scr_height-ICON_SIZE)
  1688.                 icon->y_pos = scr->scr_height-ICON_SIZE;
  1689.  
  1690.             if (icon->x_pos < 0)
  1691.                 icon->x_pos = 0;
  1692.             else if (icon->x_pos > scr->scr_width-ICON_SIZE)
  1693.                 icon->x_pos = scr->scr_width-ICON_SIZE;
  1694.     }
  1695.     }
  1696.  
  1697. #ifdef OFFIX_DND
  1698.     value = PLGetDictionaryEntry(clip_state, dDropCommand);
  1699.     if (value && PLIsString(value))
  1700.     icon->dnd_command = wstrdup(PLGetString(value));
  1701. #endif
  1702.  
  1703.     PLRelease(clip_state);
  1704.  
  1705.     return icon;
  1706. }
  1707.  
  1708.  
  1709. WDock*
  1710. wDockRestoreState(WScreen *scr, proplist_t dock_state, int type)
  1711. {
  1712.     WDock *dock;
  1713.     proplist_t apps;
  1714.     proplist_t value;
  1715.     WAppIcon *aicon, *old_top;
  1716.     int count, i;
  1717.  
  1718.  
  1719.     dock = wDockCreate(scr, type);
  1720.  
  1721.     if (!dock_state)
  1722.         return dock;
  1723.  
  1724.     if (dock_state)
  1725.         PLRetain(dock_state);
  1726.  
  1727.  
  1728.     /* restore position */
  1729.  
  1730.     value = PLGetDictionaryEntry(dock_state, dPosition);
  1731.  
  1732.     if (value) {
  1733.         if (!PLIsString(value))
  1734.             COMPLAIN("Position");
  1735.         else {
  1736.             if (sscanf(PLGetString(value), "%i,%i", &dock->x_pos,
  1737.                        &dock->y_pos)!=2)
  1738.                 COMPLAIN("Position");
  1739.  
  1740.             /* check position sanity */
  1741.             if (dock->y_pos < 0)
  1742.                 dock->y_pos = 0;
  1743.             else if (dock->y_pos > scr->scr_height-ICON_SIZE)
  1744.                 dock->y_pos = scr->scr_height - ICON_SIZE;
  1745.  
  1746.             /* This is no more needed. ??? */
  1747.             if (type == WM_CLIP) {
  1748.                 if (dock->x_pos < 0)
  1749.                     dock->x_pos = 0;
  1750.                 else if (dock->x_pos > scr->scr_width-ICON_SIZE)
  1751.                     dock->x_pos = scr->scr_width-ICON_SIZE;
  1752.             } else {
  1753.                 if (dock->x_pos >= 0) {
  1754.                     dock->x_pos = DOCK_EXTRA_SPACE;
  1755.                     dock->on_right_side = 0;
  1756.                 } else {
  1757.                     dock->x_pos = scr->scr_width - DOCK_EXTRA_SPACE - ICON_SIZE;
  1758.                     dock->on_right_side = 1;
  1759.                 }
  1760.             }
  1761.         }
  1762.     }
  1763.  
  1764.     /* restore lowered/raised state */
  1765.  
  1766.     dock->lowered = 0;
  1767.  
  1768.     value = PLGetDictionaryEntry(dock_state, dLowered);
  1769.  
  1770.     if (value) {
  1771.         if (!PLIsString(value))
  1772.             COMPLAIN("Lowered");
  1773.         else {
  1774.             if (strcasecmp(PLGetString(value), "YES")==0)
  1775.                 dock->lowered = 1;
  1776.         }
  1777.     }
  1778.  
  1779.  
  1780.     /* restore collapsed state */
  1781.  
  1782.     dock->collapsed = 0;
  1783.  
  1784.     value = PLGetDictionaryEntry(dock_state, dCollapsed);
  1785.  
  1786.     if (value) {
  1787.         if (!PLIsString(value))
  1788.             COMPLAIN("Collapsed");
  1789.         else {
  1790.             if (strcasecmp(PLGetString(value), "YES")==0)
  1791.                 dock->collapsed = 1;
  1792.         }
  1793.     }
  1794.  
  1795.  
  1796.     /* restore auto-collapsed state */
  1797.  
  1798.     value = PLGetDictionaryEntry(dock_state, dAutoCollapse);
  1799.  
  1800.     if (value) {
  1801.         if (!PLIsString(value))
  1802.             COMPLAIN("AutoCollapse");
  1803.         else {
  1804.         if (strcasecmp(PLGetString(value), "YES")==0) {
  1805.                 dock->auto_collapse = 1;
  1806.         dock->collapsed = 1;
  1807.         }
  1808.         }
  1809.     }
  1810.  
  1811.  
  1812.     /* restore auto-raise/lower state */
  1813.  
  1814.     value = PLGetDictionaryEntry(dock_state, dAutoRaiseLower);
  1815.  
  1816.     if (value) {
  1817.         if (!PLIsString(value))
  1818.             COMPLAIN("AutoRaiseLower");
  1819.         else {
  1820.         if (strcasecmp(PLGetString(value), "YES")==0) {
  1821.                 dock->auto_raise_lower = 1;
  1822.         }
  1823.         }
  1824.     }
  1825.  
  1826.     /* restore attract icons state */
  1827.  
  1828.     dock->attract_icons = 0;
  1829.  
  1830.     value = PLGetDictionaryEntry(dock_state, dAutoAttractIcons);
  1831.  
  1832.     if (value) {
  1833.         if (!PLIsString(value))
  1834.             COMPLAIN("AutoAttractIcons");
  1835.         else {
  1836.             if (strcasecmp(PLGetString(value), "YES")==0)
  1837.                 dock->attract_icons = 1;
  1838.         }
  1839.     }
  1840.  
  1841.  
  1842.     /* application list */
  1843.     
  1844.     {
  1845.     proplist_t tmp;
  1846.     char buffer[64];
  1847.     
  1848.     /*
  1849.      * When saving, it saves the dock state in
  1850.      * Applications and Applicationsnnn
  1851.      * 
  1852.      * When loading, it will first try Applicationsnnn.
  1853.      * If it does not exist, use Applications as default.
  1854.      */
  1855.     
  1856.     sprintf(buffer, "Applications%i", scr->scr_height);
  1857.  
  1858.     tmp = PLMakeString(buffer);
  1859.     apps = PLGetDictionaryEntry(dock_state, tmp);
  1860.     PLRelease(tmp);
  1861.  
  1862.     if (!apps) {
  1863.         apps = PLGetDictionaryEntry(dock_state, dApplications);
  1864.     }
  1865.     }
  1866.  
  1867.     if (!apps) {
  1868.         goto finish;
  1869.     }
  1870.  
  1871.     count = PLGetNumberOfElements(apps);
  1872.  
  1873.     if (count==0)
  1874.         goto finish;
  1875.  
  1876.     old_top = dock->icon_array[0];
  1877.  
  1878.     /* dock->icon_count is set to 1 when dock is created.
  1879.      * Since Clip is already restored, we want to keep it so for clip,
  1880.      * but for dock we may change the default top tile, so we set it to 0.
  1881.      */
  1882.     if (type == WM_DOCK)
  1883.         dock->icon_count = 0;
  1884.  
  1885.     for (i=0; i<count; i++) {
  1886.         if (dock->icon_count >= dock->max_icons) {
  1887.             wwarning(_("there are too many icons stored in dock. Ignoring what doesn't fit"));
  1888.             break;
  1889.         }
  1890.  
  1891.         value = PLGetArrayElement(apps, i);
  1892.         aicon = restore_icon_state(scr, value, type, dock->icon_count);
  1893.  
  1894.         dock->icon_array[dock->icon_count] = aicon;
  1895.  
  1896.         if (aicon) {
  1897.             aicon->dock = dock;
  1898.             aicon->x_pos = dock->x_pos + (aicon->xindex*ICON_SIZE);
  1899.             aicon->y_pos = dock->y_pos + (aicon->yindex*ICON_SIZE);
  1900.  
  1901.             if (dock->lowered)
  1902.                 ChangeStackingLevel(aicon->icon->core, WMNormalLevel);
  1903.             else
  1904.                 ChangeStackingLevel(aicon->icon->core, WMDockLevel);
  1905.  
  1906.             wCoreConfigure(aicon->icon->core, aicon->x_pos, aicon->y_pos,
  1907.                            0, 0);
  1908.  
  1909.             if (!dock->collapsed)
  1910.                 XMapWindow(dpy, aicon->icon->core->window);
  1911.             wRaiseFrame(aicon->icon->core);
  1912.  
  1913.             dock->icon_count++;
  1914.         } else if (dock->icon_count==0 && type==WM_DOCK)
  1915.             dock->icon_count++;
  1916.     }
  1917.  
  1918.     /* if the first icon is not defined, use the default */
  1919.     if (dock->icon_array[0]==NULL) {
  1920.         /* update default icon */
  1921.         old_top->x_pos = dock->x_pos;
  1922.         old_top->y_pos = dock->y_pos;
  1923.         if (dock->lowered)
  1924.             ChangeStackingLevel(old_top->icon->core, WMNormalLevel);
  1925.         else
  1926.             ChangeStackingLevel(old_top->icon->core, WMDockLevel);
  1927.         dock->icon_array[0] = old_top;
  1928.         XMoveWindow(dpy, old_top->icon->core->window, dock->x_pos, dock->y_pos);
  1929.         /* we don't need to increment dock->icon_count here because it was
  1930.          * incremented in the loop above.
  1931.          */
  1932.     } else if (old_top!=dock->icon_array[0]) {
  1933.         if (old_top == scr->clip_icon)
  1934.             scr->clip_icon = dock->icon_array[0];
  1935.         wAppIconDestroy(old_top);
  1936.     }
  1937.  
  1938. finish:
  1939.     if (dock_state)
  1940.         PLRelease(dock_state);
  1941.  
  1942.     return dock;
  1943. }
  1944.  
  1945.  
  1946.  
  1947. void
  1948. wDockLaunchWithState(WDock *dock, WAppIcon *btn, WSavedState *state)
  1949. {
  1950.     if (btn && btn->command && !btn->running && !btn->launching) {
  1951.  
  1952.         btn->drop_launch = 0;
  1953.  
  1954.         btn->pid = execCommand(btn, btn->command, state);
  1955.  
  1956.         if (btn->pid>0) {
  1957.             if (!btn->forced_dock && !btn->buggy_app) {
  1958.                 btn->launching = 1;
  1959.                 dockIconPaint(btn);
  1960.             }
  1961.         }
  1962.     } else {
  1963.         free(state);
  1964.     }
  1965. }
  1966.  
  1967.  
  1968. void
  1969. wDockDoAutoLaunch(WDock *dock, int workspace)
  1970. {
  1971.     WAppIcon *btn;
  1972.     WSavedState *state;
  1973.     int i;
  1974.  
  1975.     for (i = 0; i < dock->max_icons; i++) {
  1976.         btn = dock->icon_array[i];
  1977.         if (!btn || !btn->auto_launch)
  1978.             continue;
  1979.  
  1980.         state = wmalloc(sizeof(WSavedState));
  1981.         memset(state, 0, sizeof(WSavedState));
  1982.         state->workspace = workspace;
  1983.     /* TODO: this is klugy and is very difficult to understand
  1984.      * what's going on. Try to clean up */
  1985.         wDockLaunchWithState(dock, btn, state);
  1986.     }
  1987. }
  1988.  
  1989. #ifdef REDUCE_APPICONS
  1990. void
  1991. wDockSimulateLaunch(WDock *dock, WAppIcon *btn)
  1992. {
  1993.     if ((btn == NULL) || (dock == NULL))
  1994.     return;
  1995.  
  1996.     if (!btn->running) {
  1997.     if ((btn->icon->owner == NULL) && (btn->applist))
  1998.         btn->icon->owner = btn->applist->wapp->main_window_desc;
  1999.     if (!btn->forced_dock)
  2000.        btn->launching = 1;
  2001.         dockIconPaint(btn);
  2002.     wusleep(5000);
  2003.     }
  2004. }
  2005. #endif
  2006.  
  2007. #ifdef OFFIX_DND
  2008. static WDock*
  2009. findDock(WScreen *scr, XEvent *event, int *icon_pos)
  2010. {
  2011.     WDock *dock;
  2012.     int i;
  2013.  
  2014.     *icon_pos = -1;
  2015.     if ((dock = scr->dock)!=NULL) {
  2016.         for (i=0; i<dock->max_icons; i++) {
  2017.             if (dock->icon_array[i]
  2018.                 && dock->icon_array[i]->icon->core->window==event->xclient.window) {
  2019.                 *icon_pos = i;
  2020.                 break;
  2021.             }
  2022.         }
  2023.     }
  2024.     if (*icon_pos<0 && (dock = scr->workspaces[scr->current_workspace]->clip)!=NULL) {
  2025.         for (i=0; i<dock->max_icons; i++) {
  2026.             if (dock->icon_array[i]
  2027.                 && dock->icon_array[i]->icon->core->window==event->xclient.window) {
  2028.                 *icon_pos = i;
  2029.                 break;
  2030.             }
  2031.         }
  2032.     }
  2033.     if(*icon_pos>=0)
  2034.         return dock;
  2035.     return NULL;
  2036. }
  2037.  
  2038.  
  2039. int
  2040. wDockReceiveDNDDrop(WScreen *scr, XEvent *event)
  2041. {
  2042.     WDock *dock;
  2043.     WAppIcon *btn;
  2044.     int icon_pos;
  2045.  
  2046.     dock = findDock(scr, event, &icon_pos);
  2047.     if (!dock)
  2048.     return False;
  2049.  
  2050.     /*
  2051.      * Return True if the drop was on an application icon window.
  2052.      * In this case, let the ClientMessage handler redirect the
  2053.      * message to the app.
  2054.      */
  2055.     if (dock->icon_array[icon_pos]->icon->icon_win!=None)
  2056.         return True;
  2057.  
  2058.     if (dock->icon_array[icon_pos]->dnd_command!=NULL) {
  2059.         scr->flags.dnd_data_convertion_status = 0;
  2060.  
  2061.         btn = dock->icon_array[icon_pos];
  2062.  
  2063.         if (!btn->forced_dock) {
  2064.             btn->relaunching = btn->running;
  2065.             btn->running = 1;
  2066.         }
  2067.         if (btn->wm_instance || btn->wm_class) {
  2068.             WWindowAttributes attr;
  2069.         memset(&attr, 0, sizeof(WWindowAttributes));
  2070.             wDefaultFillAttributes(btn->icon->core->screen_ptr,
  2071.                                    btn->wm_instance,
  2072.                                    btn->wm_class, &attr, NULL, True);
  2073.  
  2074.             if (!attr.no_appicon)
  2075.                 btn->launching = 1;
  2076.             else
  2077.                 btn->running = 0;
  2078.         }
  2079.  
  2080.         btn->drop_launch = 1;
  2081.         scr->last_dock = dock;
  2082.         btn->pid = execCommand(btn, btn->dnd_command, NULL);
  2083.         if (btn->pid>0) {
  2084.             dockIconPaint(btn);
  2085.         } else {
  2086.             btn->launching = 0;
  2087.             if (!btn->relaunching) {
  2088.                 btn->running = 0;
  2089.             }
  2090.         }
  2091.     }
  2092.     return False;
  2093. }
  2094. #endif /* OFFIX_DND */
  2095.  
  2096.  
  2097.  
  2098. Bool
  2099. wDockAttachIcon(WDock *dock, WAppIcon *icon, int x, int y)
  2100. {
  2101.     WWindow *wwin;
  2102.     char **argv;
  2103.     int argc;
  2104.     int index;
  2105.  
  2106.     wwin = icon->icon->owner;
  2107.     if (icon->command==NULL) {
  2108.     icon->editing = 0;
  2109.     if (XGetCommand(dpy, wwin->client_win, &argv, &argc) && argc>0) {
  2110.  
  2111.         icon->command = FlattenStringList(argv, argc);
  2112.         XFreeStringList(argv);
  2113.     } else {
  2114.         char *command=NULL;
  2115.  
  2116. /*        icon->forced_dock = 1;*/
  2117.             if (dock->type!=WM_CLIP || !icon->attracted) {
  2118.         icon->editing = 1;
  2119.                 if (wInputDialog(dock->screen_ptr, _("Dock Icon"),
  2120.                                  _("Type the command used to launch the application"),
  2121.                  &command)) {
  2122.                     if (command && (command[0]==0 ||
  2123.                                     (command[0]=='-' && command[1]==0))) {
  2124.                         free(command);
  2125.                         command = NULL;
  2126.                     }
  2127.                     icon->command = command;
  2128.             icon->editing = 0;
  2129.                 } else {
  2130.             icon->editing = 0;
  2131.             if (command)
  2132.             free(command);
  2133.             /* If the target is the dock, reject the icon. If
  2134.              * the target is the clip, make it an attracted icon
  2135.              */
  2136.             if (dock->type==WM_CLIP) {
  2137.             icon->attracted = 1;
  2138.             if (!icon->icon->shadowed) {
  2139.                 icon->icon->shadowed = 1;
  2140.                 icon->icon->force_paint = 1;
  2141.             }
  2142.             } else {
  2143.             return False;
  2144.             }
  2145.                 }
  2146.             }
  2147.     }
  2148.     } else {
  2149.     icon->editing = 0;
  2150.     }
  2151.  
  2152.     for (index=1; index<dock->max_icons; index++)
  2153.         if (dock->icon_array[index] == NULL)
  2154.             break;
  2155.     /* if (index == dock->max_icons)
  2156.          return; */
  2157.  
  2158.     assert(index < dock->max_icons);
  2159.  
  2160.     dock->icon_array[index] = icon;
  2161.     icon->yindex = y;
  2162.     icon->xindex = x;
  2163.  
  2164.     icon->omnipresent = 0;
  2165.  
  2166.     icon->x_pos = dock->x_pos + x*ICON_SIZE;
  2167.     icon->y_pos = dock->y_pos + y*ICON_SIZE;
  2168.  
  2169.     dock->icon_count++;
  2170.  
  2171.     icon->running = 1;
  2172.     icon->launching = 0;
  2173.     icon->docked = 1;
  2174.     icon->dock = dock;
  2175.     icon->icon->core->descriptor.handle_mousedown = iconMouseDown;
  2176.     if (dock->type == WM_CLIP) {
  2177.         icon->icon->core->descriptor.handle_enternotify = clipEnterNotify;
  2178.         icon->icon->core->descriptor.handle_leavenotify = clipLeaveNotify;
  2179.     }
  2180.     icon->icon->core->descriptor.parent_type = WCLASS_DOCK_ICON;
  2181.     icon->icon->core->descriptor.parent = icon;
  2182.  
  2183.     MoveInStackListUnder(dock->icon_array[index-1]->icon->core,
  2184.                          icon->icon->core);
  2185.     wAppIconMove(icon, icon->x_pos, icon->y_pos);
  2186.     wAppIconPaint(icon);
  2187.  
  2188.     if (wPreferences.auto_arrange_icons)
  2189.         wArrangeIcons(dock->screen_ptr, True);
  2190.  
  2191. #ifdef OFFIX_DND
  2192.     if (icon->command && !icon->dnd_command) {
  2193.     icon->dnd_command = wmalloc(strlen(icon->command)+8);
  2194.     sprintf(icon->dnd_command, "%s %%d", icon->command);
  2195.     }
  2196. #endif
  2197.  
  2198.     return True;
  2199. }
  2200.  
  2201.  
  2202. void
  2203. reattachIcon(WDock *dock, WAppIcon *icon, int x, int y)
  2204. {
  2205.     int index;
  2206.  
  2207.     for(index=1; index<dock->max_icons; index++) {
  2208.         if(dock->icon_array[index] == icon)
  2209.             break;
  2210.     }
  2211.     assert(index < dock->max_icons);
  2212.  
  2213.     icon->yindex = y;
  2214.     icon->xindex = x;
  2215.  
  2216.     icon->x_pos = dock->x_pos + x*ICON_SIZE;
  2217.     icon->y_pos = dock->y_pos + y*ICON_SIZE;
  2218. }
  2219.  
  2220.  
  2221. Bool
  2222. moveIconBetweenDocks(WDock *src, WDock *dest, WAppIcon *icon, int x, int y)
  2223. {
  2224.     WWindow *wwin;
  2225.     char **argv;
  2226.     int argc;
  2227.     int index;
  2228.  
  2229.     if (src == dest)
  2230.         return True;     /* No move needed, we're already there */
  2231.  
  2232.     if (dest == NULL)
  2233.         return False;
  2234.  
  2235.     wwin = icon->icon->owner;
  2236.  
  2237.     /*
  2238.      * For the moment we can't do this if we move icons in Clip from one
  2239.      * workspace to other, because if we move two or more icons without
  2240.      * command, the dialog box will not be able to tell us to which of the
  2241.      * moved icons it applies. -Dan
  2242.      */
  2243.     if ((dest->type==WM_DOCK /*|| dest->keep_attracted*/) && icon->command==NULL) {
  2244.         if (XGetCommand(dpy, wwin->client_win, &argv, &argc) && argc>0) {
  2245.  
  2246.             icon->command = FlattenStringList(argv, argc);
  2247.             XFreeStringList(argv);
  2248.         } else {
  2249.             char *command=NULL;
  2250.  
  2251.         icon->editing = 1;
  2252. /*            icon->forced_dock = 1;*/
  2253.             if (wInputDialog(src->screen_ptr, _("Dock Icon"),
  2254.                  _("Type the command used to launch the application"),
  2255.                              &command)) {
  2256.                 if (command && (command[0]==0 ||
  2257.                                 (command[0]=='-' && command[1]==0))) {
  2258.                     free(command);
  2259.                     command = NULL;
  2260.                 }
  2261.                 icon->command = command;
  2262.             } else {
  2263.         icon->editing = 0;
  2264.         if (command)
  2265.             free(command);
  2266.         return False;
  2267.             }
  2268.         icon->editing = 0;
  2269.         }
  2270.     }
  2271.  
  2272.     if (dest->type == WM_DOCK)
  2273.         wClipMakeIconOmnipresent(icon, False);
  2274.  
  2275.     for(index=1; index<src->max_icons; index++) {
  2276.         if(src->icon_array[index] == icon)
  2277.             break;
  2278.     }
  2279.     assert(index < src->max_icons);
  2280.  
  2281.     src->icon_array[index] = NULL;
  2282.     src->icon_count--;
  2283.  
  2284.     for(index=1; index<dest->max_icons; index++) {
  2285.         if(dest->icon_array[index] == NULL)
  2286.             break;
  2287.     }
  2288.     /* if (index == dest->max_icons)
  2289.         return; */
  2290.  
  2291.     assert(index < dest->max_icons);
  2292.  
  2293.     dest->icon_array[index] = icon;
  2294.     icon->dock = dest;
  2295.  
  2296.     /* deselect the icon */
  2297.     if (icon->icon->selected)
  2298.         wIconSelect(icon->icon);
  2299.  
  2300.     if (dest->type == WM_DOCK) {
  2301.         icon->icon->core->descriptor.handle_enternotify = NULL;
  2302.         icon->icon->core->descriptor.handle_leavenotify = NULL;
  2303.     } else {
  2304.         icon->icon->core->descriptor.handle_enternotify = clipEnterNotify;
  2305.         icon->icon->core->descriptor.handle_leavenotify = clipLeaveNotify;
  2306.     }
  2307.  
  2308.     /* set it to be kept when moving to dock.
  2309.      * Unless the icon does not have a command set
  2310.      */
  2311.     if (icon->command && dest->type==WM_DOCK) {
  2312.     icon->attracted = 0;
  2313.     if (icon->icon->shadowed) {
  2314.         icon->icon->shadowed = 0;
  2315.         icon->icon->force_paint = 1;
  2316.     }
  2317.     }
  2318.  
  2319.     if (src->auto_collapse || src->auto_raise_lower)
  2320.         clipLeave(src);
  2321.  
  2322.     icon->yindex = y;
  2323.     icon->xindex = x;
  2324.  
  2325.     icon->x_pos = dest->x_pos + x*ICON_SIZE;
  2326.     icon->y_pos = dest->y_pos + y*ICON_SIZE;
  2327.  
  2328.     dest->icon_count++;
  2329.  
  2330.     MoveInStackListUnder(dest->icon_array[index-1]->icon->core,
  2331.                          icon->icon->core);
  2332.     wAppIconPaint(icon);
  2333.  
  2334.     return True;
  2335. }
  2336.  
  2337.  
  2338. void
  2339. wDockDetach(WDock *dock, WAppIcon *icon)
  2340. {
  2341.     int index;
  2342.  
  2343.     /* make the settings panel be closed */
  2344.     if (icon->panel) {
  2345.     DestroyDockAppSettingsPanel(icon->panel);
  2346.     }
  2347.  
  2348.     /* This must be called before icon->dock is set to NULL.
  2349.      * Don't move it. -Dan
  2350.      */
  2351.     wClipMakeIconOmnipresent(icon, False);
  2352.  
  2353.     icon->docked = 0;
  2354.     icon->dock = NULL;
  2355.     icon->attracted = 0;
  2356.     icon->auto_launch = 0;
  2357.     if (icon->icon->shadowed) {
  2358.     icon->icon->shadowed = 0;
  2359.     icon->icon->force_paint = 1;
  2360.     }
  2361.  
  2362.     /* deselect the icon */
  2363.     if (icon->icon->selected)
  2364.     wIconSelect(icon->icon);
  2365.  
  2366.     if (icon->command) {
  2367.     free(icon->command);
  2368.     icon->command = NULL;
  2369.     }
  2370. #ifdef OFFIX_DND
  2371.     if (icon->dnd_command) {
  2372.         free(icon->dnd_command);
  2373.         icon->dnd_command = NULL;
  2374.     }
  2375. #endif
  2376.  
  2377.     for (index=1; index<dock->max_icons; index++)
  2378.         if (dock->icon_array[index] == icon)
  2379.             break;
  2380.     assert(index < dock->max_icons);
  2381.     dock->icon_array[index] = NULL;
  2382.     icon->yindex = -1;
  2383.     icon->xindex = -1;
  2384.  
  2385.     dock->icon_count--;
  2386.  
  2387.     /* if the dock is not attached to an application or
  2388.      * the the application did not set the approriate hints yet,
  2389.      * destroy the icon */
  2390. #ifdef REDUCE_APPICONS
  2391.     if ((icon->num_apps == 0) && (!icon->running || !wApplicationOf(icon->main_window)) )
  2392. #else
  2393.     if (!icon->running || !wApplicationOf(icon->main_window))
  2394. #endif
  2395.     wAppIconDestroy(icon);
  2396.     else {
  2397.     icon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
  2398.     icon->icon->core->descriptor.handle_enternotify = NULL;
  2399.     icon->icon->core->descriptor.handle_leavenotify = NULL;
  2400.         icon->icon->core->descriptor.parent_type = WCLASS_APPICON;
  2401.     icon->icon->core->descriptor.parent = icon;
  2402.  
  2403.     ChangeStackingLevel(icon->icon->core, NORMAL_ICON_LEVEL);
  2404.  
  2405.     wAppIconPaint(icon);
  2406.         if (wPreferences.auto_arrange_icons) {
  2407.         wArrangeIcons(dock->screen_ptr, True);
  2408.     }
  2409.     }
  2410.     if (dock->auto_collapse || dock->auto_raise_lower)
  2411.         clipLeave(dock);
  2412. }
  2413.  
  2414.  
  2415. /*
  2416.  * returns the closest Dock slot index for the passed
  2417.  * coordinates.
  2418.  *
  2419.  * Returns False if icon can't be docked.
  2420.  *
  2421.  * Note: this function should NEVER alter ret_x or ret_y, unless it will
  2422.  * return True. -Dan
  2423.  */
  2424. Bool
  2425. wDockSnapIcon(WDock *dock, WAppIcon *icon, int req_x, int req_y,
  2426.           int *ret_x, int *ret_y, int redocking)
  2427. {
  2428.     WScreen *scr = dock->screen_ptr;
  2429.     int dx, dy;
  2430.     int ex_x, ex_y;
  2431.     int i, offset = ICON_SIZE/2;
  2432.     WAppIcon *aicon = NULL;
  2433.     WAppIcon *nicon = NULL;
  2434.     int max_y_icons, max_x_icons;
  2435.  
  2436.     max_x_icons = scr->scr_width/ICON_SIZE;
  2437.     max_y_icons = scr->scr_height/ICON_SIZE-1;
  2438.  
  2439.     if (wPreferences.flags.noupdates)
  2440.     return False;
  2441.  
  2442.     dx = dock->x_pos;
  2443.     dy = dock->y_pos;
  2444.  
  2445.     /* if the dock is full */
  2446.     if (!redocking &&
  2447.         (dock->icon_count >= dock->max_icons)) {
  2448.     return False;
  2449.     }
  2450.  
  2451.     /* exact position */
  2452.     if (req_y < dy)
  2453.         ex_y = (req_y - offset - dy)/ICON_SIZE;
  2454.     else
  2455.         ex_y = (req_y + offset - dy)/ICON_SIZE;
  2456.  
  2457.     if (req_x < dx)
  2458.         ex_x = (req_x - offset - dx)/ICON_SIZE;
  2459.     else
  2460.         ex_x = (req_x + offset - dx)/ICON_SIZE;
  2461.  
  2462.     /* check if the icon is outside the screen boundaries */
  2463.     if (dx + ex_x*ICON_SIZE < -ICON_SIZE+2 ||
  2464.     dx + ex_x*ICON_SIZE >= scr->scr_width-1 ||
  2465.     dy + ex_y*ICON_SIZE < -ICON_SIZE+2 ||
  2466.     dy + ex_y*ICON_SIZE >= scr->scr_height-1)
  2467.     return False;
  2468.  
  2469.     if (dock->type == WM_DOCK) {
  2470.     if (icon->dock != dock && ex_x != 0)
  2471.         return False;
  2472.  
  2473.         aicon = NULL;
  2474.     for (i=0; i<dock->max_icons; i++) {
  2475.         nicon = dock->icon_array[i];
  2476.         if (nicon && nicon->yindex == ex_y) {
  2477.         aicon = nicon;
  2478.         break;
  2479.         }
  2480.     }
  2481.  
  2482.     if (redocking) {
  2483.         int sig, done, closest;
  2484.  
  2485.         /* Possible cases when redocking:
  2486.          *
  2487.          * icon dragged out of range of any slot -> false
  2488.          * icon dragged to range of free slot
  2489.          * icon dragged to range of same slot
  2490.          * icon dragged to range of different icon
  2491.          */
  2492.         if (abs(ex_x) > DOCK_DETTACH_THRESHOLD)
  2493.         return False;
  2494.  
  2495.         if (ex_y>=0 && ex_y<=max_y_icons && (aicon==icon || !aicon)) {
  2496.                 *ret_x = 0;
  2497.                 *ret_y = ex_y;
  2498.                 return True;
  2499.         }
  2500.  
  2501.         /* start looking at the upper slot or lower? */
  2502.         if (ex_y*ICON_SIZE < (req_y + offset - dy))
  2503.         sig = 1;
  2504.         else
  2505.         sig = -1;
  2506.  
  2507.         closest = -1;
  2508.         done = 0;
  2509.         /* look for closest free slot */
  2510.         for (i=0; i<(DOCK_DETTACH_THRESHOLD+1)*2 && !done; i++) {
  2511.         int j;
  2512.  
  2513.         done = 1;
  2514.         closest = sig*(i/2) + ex_y;
  2515.         /* check if this slot is used */
  2516.         if (closest >= 0) {
  2517.             for (j = 0; j<dock->max_icons; j++) {
  2518.             if (dock->icon_array[j]
  2519.                 && dock->icon_array[j]->yindex==closest) {
  2520.                 /* slot is used by someone else */
  2521.                 if (dock->icon_array[j]!=icon)
  2522.                 done = 0;
  2523.                 break;
  2524.             }
  2525.             }
  2526.         }
  2527.         sig = -sig;
  2528.         }
  2529.         if (done && closest >= 0 && closest <= max_y_icons &&
  2530.         ((ex_y >= closest && ex_y - closest < DOCK_DETTACH_THRESHOLD+1)
  2531.         ||
  2532.          (ex_y < closest && closest - ex_y <= DOCK_DETTACH_THRESHOLD+1))) {
  2533.                 *ret_x = 0;
  2534.                 *ret_y = closest;
  2535.                 return True;
  2536.         }
  2537.     } else { /* !redocking */
  2538.  
  2539.         /* if slot is free and the icon is close enough, return it */
  2540.         if (!aicon && ex_x == 0 && ex_y >= 0 && ex_y <= max_y_icons) {
  2541.                 *ret_x = 0;
  2542.                 *ret_y = ex_y;
  2543.                 return True;
  2544.         }
  2545.     }
  2546.     } else { /* CLIP */
  2547.     int neighbours = 0;
  2548.         int start, stop, k;
  2549.  
  2550.         start = icon->omnipresent ? 0 : scr->current_workspace;
  2551.         stop  = icon->omnipresent ? scr->workspace_count : start+1;
  2552.  
  2553.         aicon = NULL;
  2554.         for (k=start; k<stop; k++) {
  2555.             WDock *tmp = scr->workspaces[k]->clip;
  2556.             if (!tmp)
  2557.                 continue;
  2558.             for (i=0; i<tmp->max_icons; i++) {
  2559.                 nicon = tmp->icon_array[i];
  2560.                 if (nicon && nicon->xindex == ex_x && nicon->yindex == ex_y) {
  2561.                     aicon = nicon;
  2562.                     break;
  2563.                 }
  2564.             }
  2565.             if (aicon)
  2566.                 break;
  2567.         }
  2568.         for (k=start; k<stop; k++) {
  2569.             WDock *tmp = scr->workspaces[k]->clip;
  2570.             if (!tmp)
  2571.                 continue;
  2572.             for (i=0; i<tmp->max_icons; i++) {
  2573.                 nicon = tmp->icon_array[i];
  2574.                 if (nicon && nicon != icon && /* Icon can't be it's own neighbour */
  2575.                     (abs(nicon->xindex - ex_x) <= CLIP_ATTACH_VICINITY &&
  2576.                      abs(nicon->yindex - ex_y) <= CLIP_ATTACH_VICINITY)) {
  2577.                     neighbours = 1;
  2578.                     break;
  2579.                 }
  2580.             }
  2581.             if (neighbours)
  2582.                 break;
  2583.         }
  2584.  
  2585.     if (neighbours && (aicon==NULL || (redocking && aicon == icon))) {
  2586.         *ret_x = ex_x;
  2587.         *ret_y = ex_y;
  2588.         return True;
  2589.     }
  2590.     }
  2591.     return False;
  2592. }
  2593.  
  2594. #define MIN(x, y)  ((x) > (y) ? (y) : (x))
  2595. #define MAX(x, y)  ((x) < (y) ? (y) : (x))
  2596.  
  2597. #define ON_SCREEN(x, y, sx, ex, sy, ey) \
  2598.     ((((x)+ICON_SIZE/2) >= (sx)) && (((y)+ICON_SIZE/2) >= (sy)) && \
  2599.     (((x) + (ICON_SIZE/2)) <= (ex)) && (((y) + (ICON_SIZE/2)) <= ey))
  2600.  
  2601.  
  2602. /*
  2603.  * returns true if it can find a free slot in the dock,
  2604.  * in which case it changes x_pos and y_pos accordingly.
  2605.  * Else returns false.
  2606.  */
  2607. Bool
  2608. wDockFindFreeSlot(WDock *dock, int *x_pos, int *y_pos)
  2609. {
  2610.     WScreen *scr = dock->screen_ptr;
  2611.     WAppIcon *btn;
  2612.     WAppIconChain *chain;
  2613.     unsigned char *slot_map;
  2614.     int mwidth;
  2615.     int r;
  2616.     int x, y;
  2617.     int i, done = False;
  2618.     int corner;
  2619.     int sx=0, sy=0, ex=scr->scr_width, ey=scr->scr_height;
  2620.     int extra_count=0;
  2621.  
  2622.     if (dock->type == WM_CLIP &&
  2623.         dock != scr->workspaces[scr->current_workspace]->clip)
  2624.         extra_count = scr->global_icon_count;
  2625.  
  2626.     /* if the dock is full */
  2627.     if (dock->icon_count+extra_count >= dock->max_icons) {
  2628.     return False;
  2629.     }
  2630.  
  2631.     if (!wPreferences.flags.nodock && scr->dock) {
  2632.         if (scr->dock->on_right_side)
  2633.             ex -= ICON_SIZE + DOCK_EXTRA_SPACE;
  2634.         else
  2635.             sx += ICON_SIZE + DOCK_EXTRA_SPACE;
  2636.     }
  2637.  
  2638.     if (ex < dock->x_pos)
  2639.         ex = dock->x_pos;
  2640.     if (sx > dock->x_pos+ICON_SIZE)
  2641.         sx = dock->x_pos+ICON_SIZE;
  2642. #define C_NONE 0
  2643. #define C_NW 1
  2644. #define C_NE 2
  2645. #define C_SW 3
  2646. #define C_SE 4
  2647.  
  2648.     /* check if clip is in a corner */
  2649.     if (dock->type==WM_CLIP) {
  2650.     if (dock->x_pos < 1 && dock->y_pos < 1)
  2651.         corner = C_NE;
  2652.     else if (dock->x_pos < 1 && dock->y_pos >= (ey-ICON_SIZE))
  2653.         corner = C_SE;
  2654.     else if (dock->x_pos >= (ex-ICON_SIZE)&& dock->y_pos >= (ey-ICON_SIZE))
  2655.         corner = C_SW;
  2656.     else if (dock->x_pos >= (ex-ICON_SIZE) && dock->y_pos < 1)
  2657.         corner = C_NW;
  2658.     else
  2659.         corner = C_NONE;
  2660.     } else
  2661.     corner = C_NONE;
  2662.  
  2663.     /* If the clip is in the corner, use only slots that are in the border
  2664.      * of the screen */
  2665.     if (corner!=C_NONE) {
  2666.     char *hmap, *vmap;
  2667.     int hcount, vcount;
  2668.  
  2669.     hcount = MIN(dock->max_icons, scr->scr_width/ICON_SIZE);
  2670.     vcount = MIN(dock->max_icons, scr->scr_height/ICON_SIZE);
  2671.     hmap = wmalloc(hcount+1);
  2672.     memset(hmap, 0, hcount+1);
  2673.     vmap = wmalloc(vcount+1);
  2674.     memset(vmap, 0, vcount+1);
  2675.  
  2676.     /* mark used positions */
  2677.     switch (corner) {
  2678.      case C_NE:
  2679.         for (i=0; i<dock->max_icons; i++) {
  2680.         btn = dock->icon_array[i];
  2681.         if (!btn)
  2682.             continue;
  2683.  
  2684.         if (btn->xindex==0 && btn->yindex > 0 && btn->yindex < vcount)
  2685.             vmap[btn->yindex] = 1;
  2686.         else if (btn->yindex==0 && btn->xindex>0 && btn->xindex<hcount)
  2687.             hmap[btn->xindex] = 1;
  2688.             }
  2689.             for (chain=scr->global_icons; chain!=NULL; chain=chain->next) {
  2690.                 btn = chain->aicon;
  2691.         if (btn->xindex==0 && btn->yindex > 0 && btn->yindex < vcount)
  2692.             vmap[btn->yindex] = 1;
  2693.         else if (btn->yindex==0 && btn->xindex>0 && btn->xindex<hcount)
  2694.             hmap[btn->xindex] = 1;
  2695.             }
  2696.             break;
  2697.      case C_NW:
  2698.         for (i=0; i<dock->max_icons; i++) {
  2699.         btn = dock->icon_array[i];
  2700.         if (!btn)
  2701.             continue;
  2702.  
  2703.         if (btn->xindex==0 && btn->yindex > 0 && btn->yindex < vcount)
  2704.             vmap[btn->yindex] = 1;
  2705.         else if (btn->yindex==0 && btn->xindex<0 &&btn->xindex>-hcount)
  2706.             hmap[-btn->xindex] = 1;
  2707.             }
  2708.             for (chain=scr->global_icons; chain!=NULL; chain=chain->next) {
  2709.                 btn = chain->aicon;
  2710.         if (btn->xindex==0 && btn->yindex > 0 && btn->yindex < vcount)
  2711.             vmap[btn->yindex] = 1;
  2712.         else if (btn->yindex==0 && btn->xindex<0 &&btn->xindex>-hcount)
  2713.             hmap[-btn->xindex] = 1;
  2714.             }
  2715.             break;
  2716.      case C_SE:
  2717.         for (i=0; i<dock->max_icons; i++) {
  2718.         btn = dock->icon_array[i];
  2719.         if (!btn)
  2720.             continue;
  2721.  
  2722.         if (btn->xindex==0 && btn->yindex < 0 && btn->yindex > -vcount)
  2723.             vmap[-btn->yindex] = 1;
  2724.         else if (btn->yindex==0 && btn->xindex>0 && btn->xindex<hcount)
  2725.             hmap[btn->xindex] = 1;
  2726.             }
  2727.             for (chain=scr->global_icons; chain!=NULL; chain=chain->next) {
  2728.                 btn = chain->aicon;
  2729.         if (btn->xindex==0 && btn->yindex < 0 && btn->yindex > -vcount)
  2730.             vmap[-btn->yindex] = 1;
  2731.         else if (btn->yindex==0 && btn->xindex>0 && btn->xindex<hcount)
  2732.             hmap[btn->xindex] = 1;
  2733.             }
  2734.             break;
  2735.      case C_SW:
  2736.      default:
  2737.         for (i=0; i<dock->max_icons; i++) {
  2738.         btn = dock->icon_array[i];
  2739.         if (!btn)
  2740.             continue;
  2741.  
  2742.         if (btn->xindex==0 && btn->yindex < 0 && btn->yindex > -vcount)
  2743.             vmap[-btn->yindex] = 1;
  2744.         else if (btn->yindex==0 && btn->xindex<0 &&btn->xindex>-hcount)
  2745.             hmap[-btn->xindex] = 1;
  2746.         }
  2747.             for (chain=scr->global_icons; chain!=NULL; chain=chain->next) {
  2748.                 btn = chain->aicon;
  2749.         if (btn->xindex==0 && btn->yindex < 0 && btn->yindex > -vcount)
  2750.             vmap[-btn->yindex] = 1;
  2751.         else if (btn->yindex==0 && btn->xindex<0 &&btn->xindex>-hcount)
  2752.             hmap[-btn->xindex] = 1;
  2753.             }
  2754.     }
  2755.     x=0; y=0;
  2756.     done = 0;
  2757.     /* search a vacant slot */
  2758.     for (i=1; i<MAX(vcount, hcount); i++) {
  2759.         if (i < vcount && vmap[i]==0) {
  2760.         /* found a slot */
  2761.         x = 0;
  2762.         y = i;
  2763.         done = 1;
  2764.         break;
  2765.         } else if (i < hcount && hmap[i]==0) {
  2766.         /* found a slot */
  2767.         x = i;
  2768.         y = 0;
  2769.         done = 1;
  2770.         break;
  2771.         }
  2772.     }
  2773.     free(vmap);
  2774.     free(hmap);
  2775.     /* If found a slot, translate and return */
  2776.         if (done) {
  2777.         if (corner==C_NW || corner==C_NE) {
  2778.         *y_pos = y;
  2779.         } else {
  2780.         *y_pos = -y;
  2781.         }
  2782.         if (corner==C_NE || corner==C_SE) {
  2783.         *x_pos = x;
  2784.         } else {
  2785.         *x_pos = -x;
  2786.         }
  2787.         return True;
  2788.     }
  2789.     /* else, try to find a slot somewhere else */
  2790.     }
  2791.  
  2792.     /* a map of mwidth x mwidth would be enough if we allowed icons to be
  2793.      * placed outside of screen */
  2794.     mwidth = (int)ceil(sqrt(dock->max_icons));
  2795.  
  2796.     /* In the worst case (the clip is in the corner of the screen),
  2797.      * the amount of icons that fit in the clip is smaller.
  2798.      * Double the map to get a safe value.
  2799.      */
  2800.     mwidth += mwidth;
  2801.  
  2802.     r = (mwidth-1)/2;
  2803.  
  2804.     slot_map = wmalloc(mwidth*mwidth);
  2805.     memset(slot_map, 0, mwidth*mwidth);
  2806.  
  2807. #define XY2OFS(x,y) (MAX(abs(x),abs(y)) > r) ? 0 : (((y)+r)*(mwidth)+(x)+r)
  2808.  
  2809.     /* mark used slots in the map. If the slot falls outside the map
  2810.      * (for example, when all icons are placed in line), ignore them. */
  2811.     for (i=0; i<dock->max_icons; i++) {
  2812.     btn = dock->icon_array[i];
  2813.     if (btn)
  2814.         slot_map[XY2OFS(btn->xindex, btn->yindex)] = 1;
  2815.     }
  2816.     for (chain=scr->global_icons; chain!=NULL; chain=chain->next) {
  2817.         slot_map[XY2OFS(chain->aicon->xindex, chain->aicon->yindex)] = 1;
  2818.     }
  2819.     /* Find closest slot from the center that is free by scanning the
  2820.      * map from the center to outward in circular passes.
  2821.      * This will not result in a neat layout, but will be optimal
  2822.      * in the sense that there will not be holes left.
  2823.      */
  2824.     done = 0;
  2825.     for (i = 1; i <= r && !done; i++) {
  2826.     int tx, ty;
  2827.  
  2828.     /* top and bottom parts of the ring */
  2829.     for (x = -i; x <= i && !done; x++) {
  2830.         tx = dock->x_pos + x*ICON_SIZE;
  2831.         y = -i;
  2832.         ty = dock->y_pos + y*ICON_SIZE;
  2833.         if (slot_map[XY2OFS(x,y)]==0
  2834.         && ON_SCREEN(tx, ty, sx, ex, sy, ey)) {
  2835.         *x_pos = x;
  2836.         *y_pos = y;
  2837.         done = 1;
  2838.         break;
  2839.         }
  2840.         y = i;
  2841.         ty = dock->y_pos + y*ICON_SIZE;
  2842.         if (slot_map[XY2OFS(x,y)]==0
  2843.         && ON_SCREEN(tx, ty, sx, ex, sy, ey)) {
  2844.         *x_pos = x;
  2845.         *y_pos = y;
  2846.         done = 1;
  2847.         break;
  2848.         }
  2849.     }
  2850.     /* left and right parts of the ring */
  2851.     for (y = -i+1; y <= i-1; y++) {
  2852.         ty = dock->y_pos + y*ICON_SIZE;
  2853.         x = -i;
  2854.         tx = dock->x_pos + x*ICON_SIZE;
  2855.         if (slot_map[XY2OFS(x,y)]==0
  2856.         && ON_SCREEN(tx, ty, sx, ex, sy, ey)) {
  2857.         *x_pos = x;
  2858.         *y_pos = y;
  2859.         done = 1;
  2860.         break;
  2861.         }
  2862.         x = i;
  2863.         tx = dock->x_pos + x*ICON_SIZE;
  2864.         if (slot_map[XY2OFS(x,y)]==0
  2865.         && ON_SCREEN(tx, ty, sx, ex, sy, ey)) {
  2866.         *x_pos = x;
  2867.         *y_pos = y;
  2868.         done = 1;
  2869.         break;
  2870.         }
  2871.     }
  2872.     }
  2873.     free(slot_map);
  2874. #undef XY2OFS
  2875.     return done;
  2876. }
  2877.  
  2878.  
  2879. static void
  2880. moveDock(WDock *dock, int new_x, int new_y)
  2881. {
  2882.     WAppIcon *btn;
  2883.     int i;
  2884.  
  2885.     dock->x_pos = new_x;
  2886.     dock->y_pos = new_y;
  2887.     for (i=0; i<dock->max_icons; i++) {
  2888.     btn = dock->icon_array[i];
  2889.         if (btn) {
  2890.             btn->x_pos = new_x + btn->xindex*ICON_SIZE;
  2891.         btn->y_pos = new_y + btn->yindex*ICON_SIZE;
  2892.         XMoveWindow(dpy, btn->icon->core->window, btn->x_pos, btn->y_pos);
  2893.     }
  2894.     }
  2895. }
  2896.  
  2897.  
  2898. static void
  2899. swapDock(WDock *dock)
  2900. {
  2901.    WScreen *scr = dock->screen_ptr;
  2902.    WAppIcon *btn;
  2903.    int x, i;
  2904.  
  2905.  
  2906.     if (dock->on_right_side) {
  2907.     x = dock->x_pos = scr->scr_width - ICON_SIZE - DOCK_EXTRA_SPACE;
  2908.     } else {
  2909.     x = dock->x_pos = DOCK_EXTRA_SPACE;
  2910.     }
  2911.  
  2912.     for (i=0; i<dock->max_icons; i++) {
  2913.     btn = dock->icon_array[i];
  2914.     if (btn) {
  2915.         btn->x_pos = x;
  2916.         XMoveWindow(dpy, btn->icon->core->window, btn->x_pos, btn->y_pos);
  2917.     }
  2918.     }
  2919.  
  2920.     wScreenUpdateUsableArea(scr);
  2921. }
  2922.  
  2923.  
  2924. static pid_t
  2925. execCommand(WAppIcon *btn, char *command, WSavedState *state)
  2926. {
  2927.     WScreen *scr = btn->icon->core->screen_ptr;
  2928.     pid_t pid;
  2929.     char **argv;
  2930.     int argc;
  2931.     char *cmdline;
  2932.  
  2933.     cmdline = ExpandOptions(scr, command);
  2934.  
  2935.     if (scr->flags.dnd_data_convertion_status || !cmdline) {
  2936.     if (cmdline)
  2937.         free(cmdline);
  2938.         if (state)
  2939.             free(state);
  2940.         return 0;
  2941.     }
  2942.  
  2943.     ParseCommand(cmdline, &argv, &argc);
  2944.  
  2945.     if (argv==NULL) {
  2946.         if (cmdline)
  2947.             free(cmdline);
  2948.         if (state)
  2949.             free(state);
  2950.     return 0;
  2951.     }
  2952.  
  2953.     if ((pid=fork())==0) {
  2954.     char **args;
  2955.     int i;
  2956.  
  2957.     SetupEnvironment(scr);
  2958.  
  2959. #ifdef HAVE_SETPGID
  2960.         setpgid(0, 0);
  2961. #endif
  2962.  
  2963.     args = malloc(sizeof(char*)*(argc+1));
  2964.     if (!args)
  2965.         exit(111);
  2966.     for (i=0; i<argc; i++) {
  2967.         args[i] = argv[i];
  2968.     }
  2969.     args[argc] = NULL;
  2970.     execvp(argv[0], args);
  2971.     exit(111);
  2972.     }
  2973.     while (argc > 0)
  2974.         free(argv[--argc]);
  2975.     free(argv);
  2976.  
  2977.     if (pid > 0) {
  2978.         if (!state) {
  2979.             state = wmalloc(sizeof(WSavedState));
  2980.             memset(state, 0, sizeof(WSavedState));
  2981.             state->hidden = -1;
  2982.             state->miniaturized = -1;
  2983.             state->shaded = -1;
  2984.             if (btn->dock==scr->dock || btn->omnipresent)
  2985.                 state->workspace = -1;
  2986.             else
  2987.                 state->workspace = scr->current_workspace;
  2988.         }
  2989.         wWindowAddSavedState(btn->wm_instance, btn->wm_class, cmdline, pid,
  2990.                  state);
  2991.         wAddDeathHandler(pid, (WDeathHandler*)trackDeadProcess,
  2992.                          btn->dock);
  2993.     } else if (state) {
  2994.         free(state);
  2995.     }
  2996.     free(cmdline);
  2997.     return pid;
  2998. }
  2999.  
  3000.  
  3001. void
  3002. wDockHideIcons(WDock *dock)
  3003. {
  3004.     int i;
  3005.  
  3006.     if (dock==NULL)
  3007.         return;
  3008.  
  3009.     for (i=1; i<dock->max_icons; i++) {
  3010.         if (dock->icon_array[i])
  3011.             XUnmapWindow(dpy, dock->icon_array[i]->icon->core->window);
  3012.     }
  3013.     dock->mapped = 0;
  3014.  
  3015.     dockIconPaint(dock->icon_array[0]);
  3016. }
  3017.  
  3018.  
  3019. void
  3020. wDockShowIcons(WDock *dock)
  3021. {
  3022.     int i, newlevel;
  3023.     WAppIcon *btn;
  3024.  
  3025.     if (dock==NULL)
  3026.         return;
  3027.  
  3028.     btn = dock->icon_array[0];
  3029.     moveDock(dock, btn->x_pos, btn->y_pos);
  3030.  
  3031.     newlevel = dock->lowered ? WMNormalLevel : WMDockLevel;
  3032.     ChangeStackingLevel(btn->icon->core, newlevel);
  3033.  
  3034.     for (i=1; i<dock->max_icons; i++) {
  3035.         if (dock->icon_array[i]) {
  3036.             MoveInStackListAbove(dock->icon_array[i]->icon->core,
  3037.                                  btn->icon->core);
  3038.             break;
  3039.         }
  3040.     }
  3041.  
  3042.     if (!dock->collapsed) {
  3043.         for (i=1; i<dock->max_icons; i++) {
  3044.             if (dock->icon_array[i]) {
  3045.                 XMapWindow(dpy, dock->icon_array[i]->icon->core->window);
  3046.             }
  3047.         }
  3048.     }
  3049.     dock->mapped = 1;
  3050.  
  3051.     dockIconPaint(btn);
  3052. }
  3053.  
  3054.  
  3055. void
  3056. wDockLower(WDock *dock)
  3057. {
  3058.     int i;
  3059.  
  3060.     for (i=0; i<dock->max_icons; i++) {
  3061.         if (dock->icon_array[i])
  3062.             wLowerFrame(dock->icon_array[i]->icon->core);
  3063.     }
  3064. }
  3065.  
  3066.  
  3067. void
  3068. wDockRaise(WDock *dock)
  3069. {
  3070.     int i;
  3071.  
  3072.     for (i=dock->max_icons-1; i>=0; i--) {
  3073.         if (dock->icon_array[i])
  3074.             wRaiseFrame(dock->icon_array[i]->icon->core);
  3075.     }
  3076. }
  3077.  
  3078.  
  3079. void
  3080. wDockRaiseLower(WDock *dock)
  3081. {
  3082.     if (!dock->icon_array[0]->icon->core->stacking->above
  3083.         ||(dock->icon_array[0]->icon->core->stacking->window_level
  3084.            !=dock->icon_array[0]->icon->core->stacking->above->stacking->window_level))
  3085.         wDockLower(dock);
  3086.     else
  3087.         wDockRaise(dock);
  3088. }
  3089.  
  3090.  
  3091. void
  3092. wDockFinishLaunch(WDock *dock, WAppIcon *icon)
  3093. {
  3094.     icon->launching = 0;
  3095.     icon->relaunching = 0;
  3096.     dockIconPaint(icon);
  3097. }
  3098.  
  3099.  
  3100. WAppIcon*
  3101. wDockFindIconForWindow(WDock *dock, Window window)
  3102. {
  3103.     WAppIcon *icon;
  3104.     int i;
  3105.  
  3106.     for (i=0; i<dock->max_icons; i++) {
  3107.     icon = dock->icon_array[i];
  3108.     if (icon && icon->main_window == window)
  3109.         return icon;
  3110.     }
  3111.     return NULL;
  3112. }
  3113.  
  3114.  
  3115. void
  3116. wDockTrackWindowLaunch(WDock *dock, Window window)
  3117. {
  3118.     WAppIcon *icon;
  3119. #ifdef REDUCE_APPICONS
  3120.     WAppIconAppList *tapplist;
  3121. #endif
  3122.     char *wm_class, *wm_instance;
  3123.     int i;
  3124.     Bool firstPass = True;
  3125.     Bool found = False;
  3126.     char *command = NULL;
  3127.  
  3128.     {
  3129.     int argc;
  3130.     char **argv;
  3131.  
  3132.     if (XGetCommand(dpy, window, &argv, &argc)) {
  3133.         if (argc > 0 && argv != NULL)
  3134.         command = FlattenStringList(argv,argc);
  3135.         if (argv) {
  3136.         XFreeStringList(argv);
  3137.         }
  3138.     }
  3139.     }
  3140.  
  3141.     if (!PropGetWMClass(window, &wm_class, &wm_instance) ||
  3142.     (!wm_class && !wm_instance))
  3143.     return;
  3144.  
  3145. retry:
  3146.     for (i=0; i<dock->max_icons; i++) {
  3147.     icon = dock->icon_array[i];
  3148.     if (!icon)
  3149.         continue;
  3150.  
  3151.     /* app is already attached to icon */
  3152.     if (icon->main_window == window) {
  3153.         found = True;
  3154.         break;
  3155.     }
  3156.  
  3157.     if ((icon->wm_instance || icon->wm_class)
  3158.         && (icon->launching
  3159.         || (dock->screen_ptr->flags.startup && !icon->running))) {
  3160.  
  3161.         if (icon->wm_instance && wm_instance &&
  3162.         strcmp(icon->wm_instance, wm_instance)!=0) {
  3163.         continue;
  3164.         }
  3165.         if (icon->wm_class && wm_class &&
  3166.         strcmp(icon->wm_class, wm_class)!=0) {
  3167.         continue;
  3168.         }
  3169.         if (firstPass && command && strcmp(icon->command, command)!=0) {
  3170.         continue;
  3171.         }
  3172.  
  3173.         if (!icon->relaunching) {
  3174.         WApplication *wapp;
  3175.  
  3176.         /* Possibly an application that was docked with dockit,
  3177.          * but the user did not update WMState to indicate that
  3178.          * it was docked by force */
  3179.         wapp = wApplicationOf(window);
  3180.         if (!wapp) {
  3181.             icon->forced_dock = 1;
  3182.             icon->running = 0;
  3183.         }
  3184.         if (!icon->forced_dock)
  3185.             icon->main_window = window;
  3186.  
  3187. #ifdef REDUCE_APPICONS
  3188.         tapplist = wmalloc(sizeof(WAppIconAppList));
  3189.         memset(tapplist, 0, sizeof(WAppIconAppList));
  3190.         tapplist->next = icon->applist;
  3191.         if (icon->applist)
  3192.            icon->applist->prev = tapplist;
  3193.         icon->applist = tapplist;
  3194.         tapplist->wapp = wApplicationOf(window);
  3195.         icon->num_apps++;
  3196. #endif
  3197.         }
  3198.         found = True;
  3199.         wDockFinishLaunch(dock, icon);
  3200.         break;
  3201.     }
  3202.     }
  3203.  
  3204.     if (firstPass && !found) {
  3205.     firstPass = False;
  3206.     goto retry;
  3207.     }
  3208.  
  3209.     if (command)
  3210.     free(command);
  3211.  
  3212.     if (wm_class)
  3213.     XFree(wm_class);
  3214.     if (wm_instance)
  3215.     XFree(wm_instance);
  3216. }
  3217.  
  3218.  
  3219.  
  3220. void
  3221. wClipUpdateForWorkspaceChange(WScreen *scr, int workspace)
  3222. {
  3223.     if (!wPreferences.flags.noclip) {
  3224.         scr->clip_icon->dock = scr->workspaces[workspace]->clip;
  3225.         if (scr->current_workspace != workspace) {
  3226.             WDock *old_clip = scr->workspaces[scr->current_workspace]->clip;
  3227.             WAppIconChain *chain = scr->global_icons;
  3228.  
  3229.             while (chain) {
  3230.                 moveIconBetweenDocks(chain->aicon->dock,
  3231.                                      scr->workspaces[workspace]->clip,
  3232.                                      chain->aicon, chain->aicon->xindex,
  3233.                                      chain->aicon->yindex);
  3234.                 if (scr->workspaces[workspace]->clip->collapsed)
  3235.                     XUnmapWindow(dpy, chain->aicon->icon->core->window);
  3236.                 chain = chain->next;
  3237.             }
  3238.  
  3239.             wDockHideIcons(old_clip);
  3240.             if (old_clip->auto_raise_lower) {
  3241.                 if (old_clip->auto_raise_magic) {
  3242.                     WMDeleteTimerHandler(old_clip->auto_raise_magic);
  3243.                     old_clip->auto_raise_magic = NULL;
  3244.                 }
  3245.                 wDockLower(old_clip);
  3246.             }
  3247.             if (old_clip->auto_collapse) {
  3248.                 if (old_clip->auto_expand_magic) {
  3249.                     WMDeleteTimerHandler(old_clip->auto_expand_magic);
  3250.                     old_clip->auto_expand_magic = NULL;
  3251.                 }
  3252.                 old_clip->collapsed = 1;
  3253.             }
  3254.             wDockShowIcons(scr->workspaces[workspace]->clip);
  3255.         }
  3256.     if (scr->flags.clip_balloon_mapped)
  3257.         showClipBalloon(scr->clip_icon->dock, workspace);
  3258.     }
  3259. }
  3260.  
  3261.  
  3262.  
  3263. static void
  3264. trackDeadProcess(pid_t pid, unsigned char status, WDock *dock)
  3265. {
  3266.     WAppIcon *icon;
  3267.     int i;
  3268.  
  3269.     for (i=0; i<dock->max_icons; i++) {
  3270.     icon = dock->icon_array[i];
  3271.     if (!icon)
  3272.         continue;
  3273.  
  3274.     if (icon->launching && icon->pid == pid) {
  3275.         if (!icon->relaunching) {
  3276.         icon->running = 0;
  3277.         icon->main_window = None;
  3278.         }
  3279.         wDockFinishLaunch(dock, icon);
  3280.         icon->pid = 0;
  3281.         if (status==111) {
  3282.         char msg[PATH_MAX];
  3283. #ifdef OFFIX_DND
  3284.         sprintf(msg, _("Could not execute command \"%s\""),
  3285.             icon->drop_launch && icon->dnd_command
  3286.             ? icon->dnd_command : icon->command);
  3287. #else
  3288.         sprintf(msg, _("Could not execute command \"%s\""),
  3289.             icon->command);
  3290. #endif
  3291.         wMessageDialog(dock->screen_ptr, _("Error"), msg,
  3292.                    _("OK"), NULL, NULL);
  3293.         }
  3294.         break;
  3295.     }
  3296.     }
  3297. }
  3298.  
  3299.  
  3300. static void
  3301. toggleLowered(WDock *dock)
  3302. {
  3303.     WAppIcon *tmp;
  3304.     int newlevel, i;
  3305.  
  3306.     /* lower/raise Dock */
  3307.     if (!dock->lowered) {
  3308.     newlevel = WMNormalLevel;
  3309.     dock->lowered = 1;
  3310.     } else {
  3311.     newlevel = WMDockLevel;
  3312.     dock->lowered = 0;
  3313.     }
  3314.  
  3315.     for (i=0; i<dock->max_icons; i++) {
  3316.     tmp = dock->icon_array[i];
  3317.     if (!tmp)
  3318.         continue;
  3319.  
  3320.     ChangeStackingLevel(tmp->icon->core, newlevel);
  3321.     if (dock->lowered)
  3322.         wLowerFrame(tmp->icon->core);
  3323.     }
  3324.  
  3325.     if (dock->type == WM_DOCK)
  3326.     wScreenUpdateUsableArea(dock->screen_ptr);
  3327. }
  3328.  
  3329.  
  3330. static void
  3331. toggleCollapsed(WDock *dock)
  3332. {
  3333.     if (dock->collapsed) {
  3334.         dock->collapsed = 0;
  3335.         wDockShowIcons(dock);
  3336.     }
  3337.     else {
  3338.         dock->collapsed = 1;
  3339.         wDockHideIcons(dock);
  3340.     }
  3341. }
  3342.  
  3343.  
  3344. static void
  3345. openDockMenu(WDock *dock, WAppIcon *aicon, XEvent *event)
  3346. {
  3347.     WScreen *scr = dock->screen_ptr;
  3348.     WObjDescriptor *desc;
  3349.     WMenuEntry *entry;
  3350.     WApplication *wapp = NULL;
  3351.     int index = 0;
  3352.     int x_pos;
  3353.     int n_selected;
  3354.     int appIsRunning = aicon->running && aicon->icon && aicon->icon->owner;
  3355.  
  3356.     if (dock->type == WM_DOCK) {
  3357.     /* keep on top */
  3358.     entry = dock->menu->entries[index];
  3359.     
  3360.     if (dock->lowered) {
  3361.         entry->text = _("Keep on Top");
  3362.     } else {
  3363.         entry->text = _("Allow Lowering");
  3364.     }
  3365.     entry->clientdata = dock;
  3366.     
  3367.     dock->menu->flags.realized = 0;
  3368.     } else {
  3369.     /* clip options */
  3370.     if (scr->clip_options)
  3371.         updateClipOptionsMenu(scr->clip_options, dock);
  3372.  
  3373.         n_selected = numberOfSelectedIcons(dock);
  3374.  
  3375.     /* Rename Workspace */
  3376.     entry = dock->menu->entries[++index];
  3377.         if (aicon == scr->clip_icon) {
  3378.             entry->callback = renameCallback;
  3379.             entry->clientdata = dock;
  3380.             entry->flags.indicator = 0;
  3381.             entry->text = _("Rename Workspace");
  3382.         } else {
  3383.             entry->callback = omnipresentCallback;
  3384.             entry->clientdata = aicon;
  3385.             if (n_selected > 0) {
  3386.                 entry->flags.indicator = 0;
  3387.                 entry->text = _("Toggle Omnipresent");
  3388.             } else {
  3389.                 entry->flags.indicator = 1;
  3390.                 entry->flags.indicator_on = aicon->omnipresent;
  3391.                 entry->flags.indicator_type = MI_CHECK;
  3392.                 entry->text = _("Omnipresent");
  3393.             }
  3394.         }
  3395.  
  3396.     /* select/unselect icon */
  3397.     entry = dock->menu->entries[++index];
  3398.         entry->clientdata = aicon;
  3399.         entry->flags.indicator_on = aicon->icon->selected;
  3400.     wMenuSetEnabled(dock->menu, index, aicon!=scr->clip_icon);
  3401.  
  3402.     /* select/unselect all icons */
  3403.     entry = dock->menu->entries[++index];
  3404.         entry->clientdata = aicon;
  3405.         if (n_selected > 0)
  3406.             entry->text = _("Unselect All Icons");
  3407.         else
  3408.             entry->text = _("Select All Icons");
  3409.     wMenuSetEnabled(dock->menu, index, dock->icon_count > 1);
  3410.  
  3411.     /* keep icon(s) */
  3412.     entry = dock->menu->entries[++index];
  3413.         entry->clientdata = aicon;
  3414.         if (n_selected > 1)
  3415.             entry->text = _("Keep Icons");
  3416.         else
  3417.             entry->text = _("Keep Icon");
  3418.     wMenuSetEnabled(dock->menu, index, dock->icon_count > 1);
  3419.  
  3420.     /* this is the workspace submenu part */
  3421.         entry = dock->menu->entries[++index];
  3422.         if (n_selected > 1)
  3423.             entry->text = _("Move Icons To");
  3424.         else
  3425.             entry->text = _("Move Icon To");
  3426.     if (scr->clip_submenu)
  3427.         updateWorkspaceMenu(scr->clip_submenu, aicon);
  3428.         wMenuSetEnabled(dock->menu, index, !aicon->omnipresent);
  3429.  
  3430.     /* remove icon(s) */
  3431.     entry = dock->menu->entries[++index];
  3432.     entry->clientdata = aicon;
  3433.         if (n_selected > 1)
  3434.             entry->text = _("Remove Icons");
  3435.         else
  3436.             entry->text = _("Remove Icon");
  3437.     wMenuSetEnabled(dock->menu, index, dock->icon_count > 1);
  3438.  
  3439.     /* attract icon(s) */
  3440.     entry = dock->menu->entries[++index];
  3441.         entry->clientdata = aicon;
  3442.  
  3443.         dock->menu->flags.realized = 0;
  3444.         wMenuRealize(dock->menu);
  3445.     }
  3446.  
  3447.     
  3448.     if (aicon->icon->owner) {
  3449.         wapp = wApplicationOf(aicon->icon->owner->main_window);
  3450.     } else {
  3451.     wapp = NULL;
  3452.     }
  3453.     
  3454.     /* launch */
  3455.     entry = dock->menu->entries[++index];
  3456.     entry->clientdata = aicon;
  3457.     wMenuSetEnabled(dock->menu, index, aicon->command!=NULL);
  3458.  
  3459.     /* unhide here */
  3460.     entry = dock->menu->entries[++index];
  3461.     entry->clientdata = aicon;
  3462.     if (wapp && wapp->flags.hidden) {
  3463.     entry->text = _("Unhide Here");
  3464.     } else {
  3465.     entry->text = _("Bring Here");
  3466.     }
  3467.     wMenuSetEnabled(dock->menu, index, appIsRunning);
  3468.  
  3469.     /* hide */
  3470.     entry = dock->menu->entries[++index];
  3471.     entry->clientdata = aicon;
  3472.     if (wapp && wapp->flags.hidden) {
  3473.     entry->text = _("Unhide");
  3474.     } else {
  3475.     entry->text = _("Hide");
  3476.     }
  3477.     wMenuSetEnabled(dock->menu, index, appIsRunning);
  3478.  
  3479.     /* settings */
  3480.     entry = dock->menu->entries[++index];
  3481.     entry->clientdata = aicon;
  3482.     wMenuSetEnabled(dock->menu, index, !aicon->editing
  3483.             && !wPreferences.flags.noupdates);
  3484.  
  3485.     /* kill */
  3486.     entry = dock->menu->entries[++index];
  3487.     entry->clientdata = aicon;
  3488.     wMenuSetEnabled(dock->menu, index, appIsRunning);
  3489.  
  3490.     if (!dock->menu->flags.realized)
  3491.     wMenuRealize(dock->menu);
  3492.  
  3493.     if (dock->type == WM_CLIP) {
  3494.     x_pos = event->xbutton.x_root+2;
  3495.     } else {
  3496.     x_pos = dock->on_right_side ?
  3497.         scr->scr_width - dock->menu->frame->core->width - 2 : 0;
  3498.     }
  3499.  
  3500.     wMenuMapAt(dock->menu, x_pos, event->xbutton.y_root+2, False);
  3501.  
  3502.     /* allow drag select */
  3503.     event->xany.send_event = True;
  3504.     desc = &dock->menu->menu->descriptor;
  3505.     (*desc->handle_mousedown)(desc, event);
  3506. }
  3507.  
  3508.  
  3509. static void
  3510. openClipWorkspaceMenu(WScreen *scr, int x, int y)
  3511. {
  3512.     if (!scr->clip_ws_menu) {
  3513.     scr->clip_ws_menu = wWorkspaceMenuMake(scr, False);
  3514.     }
  3515.     wWorkspaceMenuUpdate(scr, scr->clip_ws_menu);
  3516.     wMenuMapAt(scr->clip_ws_menu, x, y, False);
  3517. }
  3518.  
  3519.  
  3520. /******************************************************************/
  3521. static void
  3522. iconDblClick(WObjDescriptor *desc, XEvent *event)
  3523. {
  3524.     WAppIcon *btn = desc->parent;
  3525.     WDock *dock = btn->dock;
  3526.     WApplication *wapp = NULL;
  3527.     int unhideHere = 0;
  3528.  
  3529. #ifdef REDUCE_APPICONS
  3530.     if ((btn->icon->owner && !(event->xbutton.state & ControlMask)) ||
  3531.     ((btn->icon->owner == NULL) && (btn->applist != NULL))) {
  3532.         if (btn->icon->owner == NULL)
  3533.             btn->icon->owner = btn->applist->wapp->main_window_desc;
  3534. #else
  3535.     if (btn->icon->owner && !(event->xbutton.state & ControlMask)) {
  3536. #endif
  3537.     wapp = wApplicationOf(btn->icon->owner->main_window);
  3538.  
  3539.     assert(wapp!=NULL);
  3540.  
  3541.     unhideHere = (event->xbutton.state & ShiftMask);
  3542.  
  3543.         /* go to the last workspace that the user worked on the app */
  3544.     if (wapp->last_workspace != dock->screen_ptr->current_workspace
  3545.         && !unhideHere) {
  3546.         wWorkspaceChange(dock->screen_ptr, wapp->last_workspace);
  3547.     }
  3548.  
  3549.     wUnhideApplication(wapp, event->xbutton.button==Button2,
  3550.                unhideHere);
  3551.  
  3552.     if (event->xbutton.state & MOD_MASK) {
  3553.         wHideOtherApplications(btn->icon->owner);
  3554.     }
  3555.     } else {
  3556.     if (event->xbutton.button==Button1) {
  3557.  
  3558.         if (event->xbutton.state & MOD_MASK) {
  3559.                 /* raise/lower dock */
  3560.                 toggleLowered(dock);
  3561.             } else if (btn == dock->screen_ptr->clip_icon) {
  3562.         if (getClipButton(event->xbutton.x, event->xbutton.y)==CLIP_IDLE)
  3563.             toggleCollapsed(dock);
  3564.         else
  3565.             handleClipChangeWorkspace(dock->screen_ptr, event);
  3566.         } else if (btn->command) {
  3567.         if (!btn->launching &&
  3568.             (!btn->running || (event->xbutton.state & ControlMask))) {
  3569.             launchDockedApplication(btn);
  3570.                 }
  3571.             } else if (btn->xindex == 0 && btn->yindex == 0
  3572.                && btn->dock->type == WM_DOCK) {
  3573.  
  3574.         wShowGNUstepPanel(dock->screen_ptr);
  3575.         }
  3576.         }
  3577.     }
  3578. }
  3579.  
  3580.  
  3581. static void
  3582. handleDockMove(WDock *dock, WAppIcon *aicon, XEvent *event)
  3583. {
  3584.     WScreen *scr = dock->screen_ptr;
  3585.     int ofs_x=event->xbutton.x, ofs_y=event->xbutton.y;
  3586.     int x, y;
  3587.     XEvent ev;
  3588.     int grabbed = 0, swapped = 0, done;
  3589.     Pixmap ghost = None;
  3590.     int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
  3591.  
  3592. #ifdef DEBUG
  3593.     puts("moving dock");
  3594. #endif
  3595.     if (XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
  3596.              |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  3597.              GrabModeAsync, None, None, CurrentTime) !=GrabSuccess) {
  3598.     wwarning("pointer grab failed for dock move");
  3599.     }
  3600.     y = 0;
  3601.     for (x=0; x<dock->max_icons; x++) {
  3602.         if (dock->icon_array[x]!=NULL &&
  3603.             dock->icon_array[x]->yindex > y)
  3604.             y = dock->icon_array[x]->yindex;
  3605.     }
  3606.     y++;
  3607.     XResizeWindow(dpy, scr->dock_shadow, ICON_SIZE, ICON_SIZE*y);
  3608.  
  3609.     done = 0;
  3610.     while (!done) {
  3611.     WMMaskEvent(dpy, PointerMotionMask|ButtonReleaseMask|ButtonPressMask
  3612.             |ButtonMotionMask|ExposureMask, &ev);
  3613.     switch (ev.type) {
  3614.      case Expose:
  3615.         WMHandleEvent(&ev);
  3616.         break;
  3617.  
  3618.      case MotionNotify:
  3619.         if (!grabbed) {
  3620.         if (abs(ofs_x-ev.xmotion.x)>=MOVE_THRESHOLD
  3621.             || abs(ofs_y-ev.xmotion.y)>=MOVE_THRESHOLD) {
  3622.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  3623.                         |ButtonReleaseMask|ButtonPressMask,
  3624.                          wCursor[WCUR_MOVE], CurrentTime);
  3625.             grabbed=1;
  3626.         }
  3627.         break;
  3628.         }
  3629.             if (dock->type == WM_CLIP) {
  3630.                 if (ev.xmotion.x_root - ofs_x < 0) {
  3631.                     x = 0;
  3632.                 } else if (ev.xmotion.x_root - ofs_x + ICON_SIZE >
  3633.                            scr->scr_width) {
  3634.                     x = scr->scr_width - ICON_SIZE;
  3635.                 } else {
  3636.                     x = ev.xmotion.x_root - ofs_x;
  3637.                 }
  3638.                 if (ev.xmotion.y_root - ofs_y < 0) {
  3639.                     y = 0;
  3640.                 } else if (ev.xmotion.y_root - ofs_y + ICON_SIZE >
  3641.                            scr->scr_height) {
  3642.                     y = scr->scr_height - ICON_SIZE;
  3643.                 } else {
  3644.                     y = ev.xmotion.y_root - ofs_y;
  3645.                 }
  3646.                 moveDock(dock, x, y);
  3647.             } else {
  3648.             /* move vertically if pointer is inside the dock*/
  3649.         if ((dock->on_right_side &&
  3650.          ev.xmotion.x_root >= dock->x_pos - ICON_SIZE)
  3651.         || (!dock->on_right_side &&
  3652.             ev.xmotion.x_root <= dock->x_pos + ICON_SIZE*2)) {
  3653.  
  3654.         if (ev.xmotion.y_root - ofs_y < 0) {
  3655.             y = 0;
  3656.         } else if (ev.xmotion.y_root - ofs_y + ICON_SIZE >
  3657.                scr->scr_height) {
  3658.             y = scr->scr_height - ICON_SIZE;
  3659.         } else {
  3660.             y = ev.xmotion.y_root - ofs_y;
  3661.         }
  3662.                 moveDock(dock, dock->x_pos, y);
  3663.         }
  3664.         /* move horizontally to change sides */
  3665.         x = ev.xmotion.x_root - ofs_x;
  3666.         if (!dock->on_right_side) {
  3667.  
  3668.         /* is on left */
  3669.  
  3670.         if (ev.xmotion.x_root > dock->x_pos + ICON_SIZE*2) {
  3671.             XMoveWindow(dpy, scr->dock_shadow, scr->scr_width-ICON_SIZE
  3672.                       -DOCK_EXTRA_SPACE-1, dock->y_pos);
  3673.                     if (superfluous && ghost==None) {
  3674.                         ghost = MakeGhostDock(dock, dock->x_pos,
  3675.                                               scr->scr_width-ICON_SIZE
  3676.                                               -DOCK_EXTRA_SPACE-1,
  3677.                                               dock->y_pos);
  3678.                         XSetWindowBackgroundPixmap(dpy, scr->dock_shadow,
  3679.                                                    ghost);
  3680.                         XClearWindow(dpy, scr->dock_shadow);
  3681.                     }
  3682.             XMapRaised(dpy, scr->dock_shadow);
  3683.             swapped = 1;
  3684.         } else {
  3685.                     if (superfluous && ghost!=None) {
  3686.             XFreePixmap(dpy, ghost);
  3687.             ghost = None;
  3688.             }
  3689.             XUnmapWindow(dpy, scr->dock_shadow);
  3690.             swapped = 0;
  3691.         }
  3692.         } else {
  3693.         /* is on right */
  3694.         if (ev.xmotion.x_root < dock->x_pos - ICON_SIZE) {
  3695.             XMoveWindow(dpy, scr->dock_shadow,
  3696.                 DOCK_EXTRA_SPACE, dock->y_pos);
  3697.                     if (superfluous && ghost==None) {
  3698.                         ghost = MakeGhostDock(dock, dock->x_pos,
  3699.                                               DOCK_EXTRA_SPACE, dock->y_pos);
  3700.                         XSetWindowBackgroundPixmap(dpy, scr->dock_shadow,
  3701.                                                    ghost);
  3702.                         XClearWindow(dpy, scr->dock_shadow);
  3703.                     }
  3704.             XMapRaised(dpy, scr->dock_shadow);
  3705.             swapped = -1;
  3706.         } else {
  3707.             XUnmapWindow(dpy, scr->dock_shadow);
  3708.             swapped = 0;
  3709.             if (superfluous && ghost!=None) {
  3710.             XFreePixmap(dpy, ghost);
  3711.             ghost = None;
  3712.             }
  3713.         }
  3714.             }
  3715.             }
  3716.         break;
  3717.  
  3718.      case ButtonPress:
  3719.         break;
  3720.  
  3721.      case ButtonRelease:
  3722.         if (ev.xbutton.button != event->xbutton.button)
  3723.         break;
  3724.         XUngrabPointer(dpy, CurrentTime);
  3725.         XUnmapWindow(dpy, scr->dock_shadow);
  3726.         XResizeWindow(dpy, scr->dock_shadow, ICON_SIZE, ICON_SIZE);
  3727.             if (dock->type == WM_DOCK) {
  3728.                 if (swapped!=0) {
  3729.                     if (swapped>0)
  3730.                         dock->on_right_side = 1;
  3731.                     else
  3732.                         dock->on_right_side = 0;
  3733.                     swapDock(dock);
  3734.                     wArrangeIcons(scr, False);
  3735.                 }
  3736.             }
  3737.         done = 1;
  3738.         break;
  3739.     }
  3740.     }
  3741.     if (superfluous) {
  3742.     if (ghost!=None)
  3743.         XFreePixmap(dpy, ghost);
  3744.     XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
  3745.     }
  3746. #ifdef DEBUG
  3747.     puts("End dock move");
  3748. #endif
  3749. }
  3750.  
  3751.  
  3752.  
  3753. static void
  3754. handleIconMove(WDock *dock, WAppIcon *aicon, XEvent *event)
  3755. {
  3756.     WScreen *scr = dock->screen_ptr;
  3757.     Window wins[2];
  3758.     WIcon *icon = aicon->icon;
  3759.     WDock *dock2 = NULL, *last_dock = dock, *clip = NULL;
  3760.     int ondock, grabbed = 0, change_dock = 0, collapsed = 0;
  3761.     XEvent ev;
  3762.     int x = aicon->x_pos, y = aicon->y_pos;
  3763.     int ofs_x = event->xbutton.x, ofs_y = event->xbutton.y;
  3764.     int shad_x = x, shad_y = y;
  3765.     int ix = aicon->xindex, iy = aicon->yindex;
  3766.     int tmp;
  3767.     Pixmap ghost = None;
  3768.     Bool docked;
  3769.     int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
  3770.     int omnipresent = aicon->omnipresent; /* this must be cached!!! */
  3771.  
  3772.  
  3773.     if (wPreferences.flags.noupdates)
  3774.     return;
  3775.  
  3776.     if (XGrabPointer(dpy, icon->core->window, True, ButtonMotionMask
  3777.              |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  3778.              GrabModeAsync, None, None, CurrentTime) !=GrabSuccess) {
  3779. #ifdef DEBUG0
  3780.     wwarning("pointer grab failed for icon move");
  3781. #endif
  3782.     }
  3783.  
  3784.     if (!(event->xbutton.state & MOD_MASK))
  3785.     wRaiseFrame(icon->core);
  3786.  
  3787.     if (!wPreferences.flags.noclip)
  3788.         clip = scr->workspaces[scr->current_workspace]->clip;
  3789.  
  3790.     if (dock == scr->dock && !wPreferences.flags.noclip)
  3791.         dock2 = clip;
  3792.     else if (dock != scr->dock && !wPreferences.flags.nodock)
  3793.         dock2 = scr->dock;
  3794.  
  3795.     wins[0] = icon->core->window;
  3796.     wins[1] = scr->dock_shadow;
  3797.     XRestackWindows(dpy, wins, 2);
  3798.     XMoveResizeWindow(dpy, scr->dock_shadow, aicon->x_pos, aicon->y_pos,
  3799.               ICON_SIZE, ICON_SIZE);
  3800.     if (superfluous) {
  3801.     if (icon->pixmap!=None)
  3802.         ghost = MakeGhostIcon(scr, icon->pixmap);
  3803.     else
  3804.         ghost = MakeGhostIcon(scr, icon->core->window);
  3805.  
  3806.     XSetWindowBackgroundPixmap(dpy, scr->dock_shadow, ghost);
  3807.     XClearWindow(dpy, scr->dock_shadow);
  3808.     }
  3809.     XMapWindow(dpy, scr->dock_shadow);
  3810.  
  3811.     ondock = 1;
  3812.  
  3813.  
  3814.     while(1) {
  3815.     XMaskEvent(dpy, PointerMotionMask|ButtonReleaseMask|ButtonPressMask
  3816.            |ButtonMotionMask|ExposureMask, &ev);
  3817.     switch (ev.type) {
  3818.      case Expose:
  3819.         WMHandleEvent(&ev);
  3820.         break;
  3821.  
  3822.      case MotionNotify:
  3823.         if (!grabbed) {
  3824.         if (abs(ofs_x-ev.xmotion.x)>=MOVE_THRESHOLD
  3825.             || abs(ofs_y-ev.xmotion.y)>=MOVE_THRESHOLD) {
  3826.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  3827.                         |ButtonReleaseMask|ButtonPressMask,
  3828.                          wCursor[WCUR_MOVE], CurrentTime);
  3829.             grabbed=1;
  3830.         } else {
  3831.             break;
  3832.         }
  3833.         }
  3834.  
  3835.             if (omnipresent) {
  3836.                 int i;
  3837.                 for (i=0; i<scr->workspace_count; i++) {
  3838.                     if (i == scr->current_workspace)
  3839.                         continue;
  3840.                     wDockShowIcons(scr->workspaces[i]->clip);
  3841.                 }
  3842.             }
  3843.  
  3844.         x = ev.xmotion.x_root - ofs_x;
  3845.         y = ev.xmotion.y_root - ofs_y;
  3846.             tmp = wDockSnapIcon(dock, aicon, x, y, &ix, &iy, True);
  3847.             if (tmp && dock2) {
  3848.                 change_dock = 0;
  3849.                 if (last_dock != dock && collapsed) {
  3850.                     last_dock->collapsed = 1;
  3851.                     wDockHideIcons(last_dock);
  3852.                     collapsed = 0;
  3853.                 }
  3854.                 if (!collapsed && (collapsed = dock->collapsed)) {
  3855.                     dock->collapsed = 0;
  3856.                     wDockShowIcons(dock);
  3857.                 }
  3858.                 if (dock->auto_raise_lower)
  3859.                     wDockRaise(dock);
  3860.                 last_dock = dock;
  3861.             } else if (dock2) {
  3862.                 tmp = wDockSnapIcon(dock2, aicon, x, y, &ix, &iy, False);
  3863.                 if (tmp) {
  3864.                     change_dock = 1;
  3865.                     if (last_dock != dock2 && collapsed) {
  3866.                         last_dock->collapsed = 1;
  3867.                         wDockHideIcons(last_dock);
  3868.                         collapsed = 0;
  3869.                     }
  3870.                     if (!collapsed && (collapsed = dock2->collapsed)) {
  3871.                         dock2->collapsed = 0;
  3872.                         wDockShowIcons(dock2);
  3873.                     }
  3874.                     if (dock2->auto_raise_lower)
  3875.                         wDockRaise(dock2);
  3876.                     last_dock = dock2;
  3877.                 }
  3878.             }
  3879.             if (aicon->launching
  3880.         || aicon->lock
  3881.         || (aicon->running && !(ev.xmotion.state & MOD_MASK))
  3882.         || (!aicon->running && tmp)) {
  3883.                 shad_x = last_dock->x_pos + ix*wPreferences.icon_size;
  3884.                 shad_y = last_dock->y_pos + iy*wPreferences.icon_size;
  3885.  
  3886.         XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
  3887.  
  3888.         if (!ondock) {
  3889.             XMapWindow(dpy, scr->dock_shadow);
  3890.         }
  3891.         ondock = 1;
  3892.         } else {
  3893.                 if (ondock) {
  3894.                     XUnmapWindow(dpy, scr->dock_shadow);
  3895.                 }
  3896.         ondock = 0;
  3897.         }
  3898.         XMoveWindow(dpy, icon->core->window, x, y);
  3899.         break;
  3900.  
  3901.      case ButtonPress:
  3902.         break;
  3903.  
  3904.      case ButtonRelease:
  3905.         if (ev.xbutton.button != event->xbutton.button)
  3906.         break;
  3907.         XUngrabPointer(dpy, CurrentTime);
  3908.         if (ondock) {
  3909.         SlideWindow(icon->core->window, x, y, shad_x, shad_y);
  3910.                 XUnmapWindow(dpy, scr->dock_shadow);
  3911.                 if (!change_dock) {
  3912.                     reattachIcon(dock, aicon, ix, iy);
  3913.                     if (clip && dock!=clip && clip->auto_raise_lower)
  3914.                         wDockLower(clip);
  3915.                 } else {
  3916.                     docked = moveIconBetweenDocks(dock, dock2, aicon, ix, iy);
  3917.             if (!docked) {
  3918.             /* Slide it back if dock rejected it */
  3919.             SlideWindow(icon->core->window, x, y, aicon->x_pos,
  3920.                     aicon->y_pos);
  3921.             reattachIcon(dock, aicon, aicon->xindex,aicon->yindex);
  3922.             }
  3923.                     if (last_dock->type==WM_CLIP && last_dock->auto_collapse) {
  3924.                         collapsed = 0;
  3925.                     }
  3926.                 }
  3927.         } else {
  3928.         aicon->x_pos = x;
  3929.         aicon->y_pos = y;
  3930.                 if (superfluous) {
  3931.             if (!aicon->running && !wPreferences.no_animations) {
  3932.             /* We need to deselect it, even if is deselected in
  3933.              * wDockDetach(), because else DoKaboom() will fail.
  3934.              */
  3935.             if (aicon->icon->selected)
  3936.                 wIconSelect(aicon->icon);
  3937.  
  3938. #ifdef WMSOUND
  3939.             wSoundPlay(WMSOUND_KABOOM);
  3940. #endif
  3941.             DoKaboom(scr,aicon->icon->core->window, x, y);
  3942. #ifdef WMSOUND
  3943.             } else {
  3944.                 wSoundPlay(WMSOUND_UNDOCK);
  3945. #endif
  3946.             }
  3947. #ifdef WMSOUND
  3948.         } else {
  3949.             wSoundPlay(WMSOUND_UNDOCK);
  3950. #endif
  3951.                 }
  3952.                 if (clip && clip->auto_raise_lower)
  3953.                     wDockLower(clip);
  3954.         wDockDetach(dock, aicon);
  3955.             }
  3956.             if (collapsed) {
  3957.                 last_dock->collapsed = 1;
  3958.                 wDockHideIcons(last_dock);
  3959.                 collapsed = 0;
  3960.             }
  3961.             if (superfluous) {
  3962.         if (ghost!=None)
  3963.             XFreePixmap(dpy, ghost);
  3964.         XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
  3965.             }
  3966.             if (omnipresent) {
  3967.                 int i;
  3968.                 for (i=0; i<scr->workspace_count; i++) {
  3969.                     if (i == scr->current_workspace)
  3970.                         continue;
  3971.                     wDockHideIcons(scr->workspaces[i]->clip);
  3972.                 }
  3973.             }
  3974.  
  3975. #ifdef DEBUG
  3976.         puts("End icon move");
  3977. #endif
  3978.         return;
  3979.     }
  3980.     }
  3981. }
  3982.  
  3983.  
  3984. static int
  3985. getClipButton(int px, int py)
  3986. {
  3987.     int pt = (CLIP_BUTTON_SIZE+2)*ICON_SIZE/64;
  3988.  
  3989.     if (px < 0 || py < 0 || px >= ICON_SIZE || py >= ICON_SIZE)
  3990.     return CLIP_IDLE;
  3991.  
  3992.     if (py <= pt-((int)ICON_SIZE-1-px))
  3993.     return CLIP_FORWARD;
  3994.     else if (px <= pt-((int)ICON_SIZE-1-py))
  3995.     return CLIP_REWIND;
  3996.  
  3997.     return CLIP_IDLE;
  3998. }
  3999.  
  4000.  
  4001. static void
  4002. handleClipChangeWorkspace(WScreen *scr, XEvent *event)
  4003. {
  4004.     XEvent ev;
  4005.     int done, direction, new_ws;
  4006.     int new_dir;
  4007.     WDock *clip = scr->clip_icon->dock;
  4008.  
  4009.     direction = getClipButton(event->xbutton.x, event->xbutton.y);
  4010.  
  4011.     clip->lclip_button_pushed = direction==CLIP_REWIND;
  4012.     clip->rclip_button_pushed = direction==CLIP_FORWARD;
  4013.  
  4014.     wClipIconPaint(scr->clip_icon);
  4015.     done = 0;
  4016.     while(!done) {
  4017.     WMMaskEvent(dpy, ExposureMask|ButtonMotionMask|ButtonReleaseMask
  4018.             |ButtonPressMask, &ev);
  4019.         switch (ev.type) {
  4020.         case Expose:
  4021.             WMHandleEvent(&ev);
  4022.             break;
  4023.  
  4024.         case MotionNotify:
  4025.             new_dir = getClipButton(ev.xmotion.x, ev.xmotion.y);
  4026.             if (new_dir != direction) {
  4027.         direction = new_dir;
  4028.         clip->lclip_button_pushed = direction==CLIP_REWIND;
  4029.         clip->rclip_button_pushed = direction==CLIP_FORWARD;
  4030.                 wClipIconPaint(scr->clip_icon);
  4031.             }
  4032.             break;
  4033.  
  4034.     case ButtonPress:
  4035.         break;
  4036.  
  4037.         case ButtonRelease:
  4038.         if (ev.xbutton.button == event->xbutton.button)
  4039.         done = 1;
  4040.         }
  4041.     }
  4042.  
  4043.     clip->lclip_button_pushed = 0;
  4044.     clip->rclip_button_pushed = 0;
  4045.  
  4046.     new_ws = wPreferences.ws_advance || (event->xbutton.state & ControlMask);
  4047.  
  4048.     if (direction == CLIP_FORWARD) {
  4049.         if (scr->current_workspace < scr->workspace_count-1)
  4050.             wWorkspaceChange(scr, scr->current_workspace+1);
  4051.         else if (new_ws && scr->current_workspace < MAX_WORKSPACES-1)
  4052.             wWorkspaceChange(scr, scr->current_workspace+1);
  4053.         else if (wPreferences.ws_cycle)
  4054.             wWorkspaceChange(scr, 0);
  4055.     }
  4056.     else if (direction == CLIP_REWIND) {
  4057.         if (scr->current_workspace > 0)
  4058.             wWorkspaceChange(scr, scr->current_workspace-1);
  4059.         else if (scr->current_workspace==0 && wPreferences.ws_cycle)
  4060.             wWorkspaceChange(scr, scr->workspace_count-1);
  4061.     }
  4062.  
  4063.     wClipIconPaint(scr->clip_icon);
  4064. }
  4065.  
  4066.  
  4067. static void
  4068. iconMouseDown(WObjDescriptor *desc, XEvent *event)
  4069. {
  4070.     WAppIcon *aicon = desc->parent;
  4071.     WDock *dock = aicon->dock;
  4072.     WScreen *scr = aicon->icon->core->screen_ptr;
  4073.  
  4074.     if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
  4075.     return;
  4076.  
  4077.     scr->last_dock = dock;
  4078.  
  4079.     if (dock->menu->flags.mapped)
  4080.     wMenuUnmap(dock->menu);
  4081.  
  4082.     if (IsDoubleClick(scr, event)) {
  4083.     /* double-click was not in the main clip icon */
  4084.         if (dock->type != WM_CLIP || aicon->xindex!=0 || aicon->yindex!=0
  4085.         || getClipButton(event->xbutton.x, event->xbutton.y)==CLIP_IDLE) {
  4086.             iconDblClick(desc, event);
  4087.             return;
  4088.         }
  4089.     }
  4090.  
  4091.     if (dock->type == WM_CLIP && scr->flags.clip_balloon_mapped) {
  4092.     XUnmapWindow(dpy, scr->clip_balloon);
  4093.     scr->flags.clip_balloon_mapped = 0;
  4094.     }
  4095.  
  4096. #ifdef DEBUG
  4097.     puts("handling dock");
  4098. #endif
  4099.     if (event->xbutton.button == Button1) {
  4100.         if (event->xbutton.state & MOD_MASK)
  4101.             wDockLower(dock);
  4102.         else
  4103.             wDockRaise(dock);
  4104.  
  4105.         if ((event->xbutton.state & ShiftMask) && aicon!=scr->clip_icon &&
  4106.             dock->type!=WM_DOCK) {
  4107.             wIconSelect(aicon->icon);
  4108.             return;
  4109.         }
  4110.  
  4111.         if (aicon->yindex==0 && aicon->xindex==0) {
  4112.             if (getClipButton(event->xbutton.x, event->xbutton.y)!=CLIP_IDLE
  4113.         && dock->type==WM_CLIP)
  4114.                 handleClipChangeWorkspace(scr, event);
  4115.             else
  4116.                 handleDockMove(dock, aicon, event);
  4117.         } else
  4118.         handleIconMove(dock, aicon, event);
  4119.  
  4120.     } else if (event->xbutton.button==Button2 && dock->type==WM_CLIP &&
  4121.                aicon==scr->clip_icon) {
  4122.         openClipWorkspaceMenu(scr, event->xbutton.x_root+2,
  4123.                   event->xbutton.y_root+2);
  4124.         if (scr->clip_ws_menu) {
  4125.             WMenu *menu;
  4126.         menu = scr->clip_ws_menu;
  4127.             desc = &menu->menu->descriptor;
  4128.  
  4129.             event->xany.send_event = True;
  4130.             (*desc->handle_mousedown)(desc, event);
  4131.         }
  4132.     } else if (event->xbutton.button==Button2 && dock->type==WM_CLIP &&
  4133.                (event->xbutton.state & ShiftMask) && aicon!=scr->clip_icon) {
  4134.         wClipMakeIconOmnipresent(aicon, !aicon->omnipresent);
  4135.     } else if (event->xbutton.button == Button3) {
  4136.     if (event->xbutton.send_event &&
  4137.         XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
  4138.              |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  4139.              GrabModeAsync, None, None, CurrentTime) !=GrabSuccess) {
  4140.         wwarning("pointer grab failed for dockicon menu");
  4141.         return;
  4142.     }
  4143.  
  4144.     openDockMenu(dock, aicon, event);
  4145.     }
  4146. }
  4147.  
  4148.  
  4149. static void
  4150. showClipBalloon(WDock *dock, int workspace)
  4151. {
  4152.     int w, h;
  4153.     int x, y;
  4154.     WScreen *scr = dock->screen_ptr;
  4155.     char *text;
  4156.     Window stack[2];
  4157.  
  4158.     scr->flags.clip_balloon_mapped = 1;
  4159.     XMapWindow(dpy, scr->clip_balloon);
  4160.  
  4161.     text = scr->workspaces[workspace]->name;
  4162.  
  4163.     w = WMWidthOfString(scr->clip_title_font, text, strlen(text));
  4164.  
  4165.     h = WMFontHeight(scr->clip_title_font);
  4166.     XResizeWindow(dpy, scr->clip_balloon, w, h);
  4167.  
  4168.     x = dock->x_pos + CLIP_BUTTON_SIZE*ICON_SIZE/64;
  4169.     y = dock->y_pos + ICON_SIZE - WMFontHeight(scr->clip_title_font) - 3;
  4170.  
  4171.     if (x+w > scr->scr_width) {
  4172.     x = scr->scr_width - w;
  4173.         if (dock->y_pos + ICON_SIZE + h > scr->scr_height)
  4174.             y = dock->y_pos - h - 1;
  4175.         else
  4176.             y = dock->y_pos + ICON_SIZE;
  4177.         XRaiseWindow(dpy, scr->clip_balloon);
  4178.     } else {
  4179.     stack[0] = scr->clip_icon->icon->core->window;
  4180.     stack[1] = scr->clip_balloon;
  4181.     XRestackWindows(dpy, stack, 2);
  4182.     }
  4183.     XMoveWindow(dpy, scr->clip_balloon, x, y);
  4184.     XSetForeground(dpy, scr->clip_title_gc,
  4185.            scr->clip_title_pixel[CLIP_NORMAL]);
  4186.     XClearWindow(dpy, scr->clip_balloon);
  4187.     WMDrawString(scr->wmscreen, scr->clip_balloon, scr->clip_title_gc,
  4188.          scr->clip_title_font, 0, 0, text, strlen(text));
  4189. }
  4190.  
  4191.  
  4192. static void
  4193. clipEnterNotify(WObjDescriptor *desc, XEvent *event)
  4194. {
  4195.     WAppIcon *btn = (WAppIcon*)desc->parent;
  4196.     WDock *dock;
  4197.     WScreen *scr;
  4198.  
  4199.     assert(event->type==EnterNotify);
  4200.  
  4201.     if(desc->parent_type!=WCLASS_DOCK_ICON)
  4202.         return;
  4203.  
  4204.     scr = btn->icon->core->screen_ptr;
  4205.     if (!btn->omnipresent)
  4206.         dock = btn->dock;
  4207.     else
  4208.         dock = scr->workspaces[scr->current_workspace]->clip;
  4209.  
  4210.     if (!dock || dock->type!=WM_CLIP)
  4211.         return;
  4212.  
  4213.     /* The auto raise/lower code */
  4214.     if (dock->auto_lower_magic) {
  4215.         WMDeleteTimerHandler(dock->auto_lower_magic);
  4216.         dock->auto_lower_magic = NULL;
  4217.     }
  4218.     if (dock->auto_raise_lower && !dock->auto_raise_magic) {
  4219.         dock->auto_raise_magic = WMAddTimerHandler(AUTO_RAISE_DELAY,
  4220.                                                    clipAutoRaise,
  4221.                                                    (void *)dock);
  4222.     }
  4223.  
  4224.     /* The auto expand/collapse code */
  4225.     if (dock->auto_collapse_magic) {
  4226.         WMDeleteTimerHandler(dock->auto_collapse_magic);
  4227.         dock->auto_collapse_magic = NULL;
  4228.     }
  4229.     if (dock->auto_collapse && !dock->auto_expand_magic) {
  4230.         dock->auto_expand_magic = WMAddTimerHandler(AUTO_EXPAND_DELAY,
  4231.                                                     clipAutoExpand,
  4232.                                                     (void *)dock);
  4233.     }
  4234.  
  4235.     if (btn->xindex == 0 && btn->yindex == 0)
  4236.     showClipBalloon(dock, dock->screen_ptr->current_workspace);
  4237.     else {
  4238.     if (dock->screen_ptr->flags.clip_balloon_mapped) {
  4239.         XUnmapWindow(dpy, dock->screen_ptr->clip_balloon);
  4240.         dock->screen_ptr->flags.clip_balloon_mapped = 0;
  4241.     }
  4242.     }
  4243. }
  4244.  
  4245.  
  4246. static void
  4247. clipLeave(WDock *dock)
  4248. {
  4249.     XEvent event;
  4250.     WObjDescriptor *desc = NULL;
  4251.  
  4252.     if (!dock || dock->type!=WM_CLIP)
  4253.     return;
  4254.  
  4255.     if (XCheckTypedEvent(dpy, EnterNotify, &event)!=False) {
  4256.         if (XFindContext(dpy, event.xcrossing.window, wWinContext,
  4257.                          (XPointer *)&desc)!=XCNOENT
  4258.             && desc && desc->parent_type==WCLASS_DOCK_ICON
  4259.             && ((WAppIcon*)desc->parent)->dock
  4260.             && ((WAppIcon*)desc->parent)->dock->type==WM_CLIP) {
  4261.             /* We didn't left the Clip yet */
  4262.             XPutBackEvent(dpy, &event);
  4263.             return;
  4264.         }
  4265.  
  4266.         XPutBackEvent(dpy, &event);
  4267.     } else {
  4268.         /* We entered a withdrawn window, so we're still in Clip */
  4269.         return;
  4270.     }
  4271.  
  4272.     if (dock->auto_raise_magic) {
  4273.         WMDeleteTimerHandler(dock->auto_raise_magic);
  4274.         dock->auto_raise_magic = NULL;
  4275.     }
  4276.     if (dock->auto_raise_lower && !dock->auto_lower_magic) {
  4277.         dock->auto_lower_magic = WMAddTimerHandler(AUTO_LOWER_DELAY,
  4278.                                                    clipAutoLower,
  4279.                                                    (void *)dock);
  4280.     }
  4281.  
  4282.     if (dock->auto_expand_magic) {
  4283.         WMDeleteTimerHandler(dock->auto_expand_magic);
  4284.         dock->auto_expand_magic = NULL;
  4285.     }
  4286.     if (dock->auto_collapse && !dock->auto_collapse_magic) {
  4287.         dock->auto_collapse_magic = WMAddTimerHandler(AUTO_COLLAPSE_DELAY,
  4288.                                                       clipAutoCollapse,
  4289.                                                       (void *)dock);
  4290.     }
  4291. }
  4292.  
  4293.  
  4294. static void
  4295. clipLeaveNotify(WObjDescriptor *desc, XEvent *event)
  4296. {
  4297.     WAppIcon *btn = (WAppIcon*)desc->parent;
  4298.  
  4299.     assert(event->type==LeaveNotify);
  4300.  
  4301.     if(desc->parent_type!=WCLASS_DOCK_ICON)
  4302.         return;
  4303.  
  4304.     clipLeave(btn->dock);
  4305. }
  4306.  
  4307.  
  4308. static void
  4309. clipAutoCollapse(void *cdata)
  4310. {
  4311.     WDock *dock = (WDock *)cdata;
  4312.  
  4313.     if (dock->type!=WM_CLIP)
  4314.         return;
  4315.  
  4316.     if (dock->auto_collapse) {
  4317.         dock->collapsed = 1;
  4318.         wDockHideIcons(dock);
  4319.     }
  4320.     dock->auto_collapse_magic = NULL;
  4321. }
  4322.  
  4323.  
  4324. static void
  4325. clipAutoExpand(void *cdata)
  4326. {
  4327.     WDock *dock = (WDock *)cdata;
  4328.  
  4329.     if (dock->type!=WM_CLIP)
  4330.         return;
  4331.  
  4332.     if (dock->auto_collapse) {
  4333.         dock->collapsed = 0;
  4334.         wDockShowIcons(dock);
  4335.     }
  4336.     dock->auto_expand_magic = NULL;
  4337. }
  4338.  
  4339.  
  4340. static void
  4341. clipAutoLower(void *cdata)
  4342. {
  4343.     WDock *dock = (WDock *)cdata;
  4344.  
  4345.     if (dock->type!=WM_CLIP)
  4346.         return;
  4347.  
  4348.     if (dock->auto_raise_lower)
  4349.         wDockLower(dock);
  4350.  
  4351.     dock->auto_lower_magic = NULL;
  4352. }
  4353.  
  4354.  
  4355. static void
  4356. clipAutoRaise(void *cdata)
  4357. {
  4358.     WDock *dock = (WDock *)cdata;
  4359.  
  4360.     if (dock->type!=WM_CLIP)
  4361.         return;
  4362.  
  4363.     if (dock->auto_raise_lower)
  4364.         wDockRaise(dock);
  4365.  
  4366.     if (dock->screen_ptr->flags.clip_balloon_mapped) {
  4367.         showClipBalloon(dock, dock->screen_ptr->current_workspace);
  4368.     }
  4369.  
  4370.     dock->auto_raise_magic = NULL;
  4371. }
  4372.  
  4373.  
  4374. static Bool
  4375. iconCanBeOmnipresent(WAppIcon *aicon)
  4376. {
  4377.     WScreen *scr = aicon->icon->core->screen_ptr;
  4378.     WDock *clip;
  4379.     WAppIcon *btn;
  4380.     int i, j;
  4381.  
  4382.     for (i=0; i<scr->workspace_count; i++) {
  4383.         clip = scr->workspaces[i]->clip;
  4384.  
  4385.         if (clip == aicon->dock)
  4386.             continue;
  4387.  
  4388.         if (clip->icon_count + scr->global_icon_count >= clip->max_icons)
  4389.             return False; /* Clip is full in some workspace */
  4390.  
  4391.         for (j=0; j<clip->max_icons; j++) {
  4392.             btn = clip->icon_array[j];
  4393.             if(btn && btn->xindex==aicon->xindex && btn->yindex==aicon->yindex)
  4394.                 return False;
  4395.         }
  4396.     }
  4397.  
  4398.     return True;
  4399. }
  4400.  
  4401.  
  4402. int
  4403. wClipMakeIconOmnipresent(WAppIcon *aicon, int omnipresent)
  4404. {
  4405.     WScreen *scr = aicon->icon->core->screen_ptr;
  4406.     WAppIconChain *new_entry, *tmp, *tmp1;
  4407.     int status = WO_SUCCESS;
  4408.  
  4409.     if ((scr->dock && aicon->dock==scr->dock) || aicon==scr->clip_icon) {
  4410.         return WO_NOT_APPLICABLE;
  4411.     }
  4412.  
  4413.     if (aicon->omnipresent == omnipresent)
  4414.         return WO_SUCCESS;
  4415.  
  4416.     if (omnipresent) {
  4417.         if (iconCanBeOmnipresent(aicon)) {
  4418.             aicon->omnipresent = 1;
  4419.             new_entry = wmalloc(sizeof(WAppIconChain));
  4420.             new_entry->aicon = aicon;
  4421.             new_entry->next = scr->global_icons;
  4422.             scr->global_icons = new_entry;
  4423.             scr->global_icon_count++;
  4424.         } else {
  4425.             aicon->omnipresent = 0;
  4426.             status = WO_FAILED;
  4427.         }
  4428.     } else {
  4429.         aicon->omnipresent = 0;
  4430.         if (aicon == scr->global_icons->aicon) {
  4431.             tmp = scr->global_icons->next;
  4432.             free(scr->global_icons);
  4433.             scr->global_icons = tmp;
  4434.             scr->global_icon_count--;
  4435.         } else {
  4436.             tmp = scr->global_icons;
  4437.             while (tmp->next) {
  4438.                 if (tmp->next->aicon == aicon) {
  4439.                     tmp1 = tmp->next->next;
  4440.                     free(tmp->next);
  4441.                     tmp->next = tmp1;
  4442.                     scr->global_icon_count--;
  4443.                     break;
  4444.                 }
  4445.                 tmp = tmp->next;
  4446.             }
  4447.         }
  4448.     }
  4449.  
  4450.     wAppIconPaint(aicon);
  4451.  
  4452.     return status;
  4453. }
  4454.  
  4455.